Merge branch 'main' into feature/tree-item-ancestors

This commit is contained in:
Mads Rasmussen
2024-03-19 13:49:19 +01:00
117 changed files with 988 additions and 1020 deletions

View File

@@ -41,6 +41,9 @@ playwright/.cache/
# storybook
storybook-static/
# API Docs
api-docs/
custom-elements.json
# JSON for HTML Custom Data

View File

@@ -19,7 +19,7 @@ There are two ways to use this:
1. Checkout the `v14/dev` branch of [Umbraco-CMS](https://github.com/umbraco/Umbraco-cms/tree/v14/dev)
2. Run `git submodule update --init` to initialize and pull down the backoffice repository
1. If you are using a Git GUI client, you might need to do this manually
3. Go to src/Umbraco.Web.UI.New or switch default startup project to "Umbraco.Web.UI.New"
3. Go to src/Umbraco.Web.UI or switch default startup project to "Umbraco.Web.UI"
4. Start the backend server: `dotnet run` or run the project from your IDE
5. Access https://localhost:44339/umbraco and complete the installation of Umbraco
6. You should see the log in screen after installation
@@ -28,7 +28,7 @@ There are two ways to use this:
### Running with Vite
1. Perform steps 1 to 5 from before
2. Open this file in an editor: `src/Umbraco.Web.UI.New/appsettings.Development.json`
2. Open this file in an editor: `src/Umbraco.Web.UI/appsettings.Development.json`
3. Add this to the Umbraco.CMS section to override the backoffice host:
```json

View File

@@ -75,6 +75,7 @@
"storybook": "^7.6.17",
"tiny-glob": "^0.2.9",
"tsc-alias": "^1.8.8",
"typedoc": "^0.25.10",
"typescript": "^5.3.3",
"typescript-json-schema": "^0.63.0",
"vite": "^5.1.1",
@@ -8612,6 +8613,12 @@
"node": ">=8"
}
},
"node_modules/ansi-sequence-parser": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.1.tgz",
"integrity": "sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg==",
"dev": true
},
"node_modules/ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
@@ -14308,6 +14315,12 @@
"node": ">=6"
}
},
"node_modules/jsonc-parser": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz",
"integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==",
"dev": true
},
"node_modules/jsonfile": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
@@ -14806,6 +14819,12 @@
"integrity": "sha512-g2JVS1v2xVypOyMRrWH5lFhJwAftBvAn732Ig4VqS60+4MtL1F+bsbI8wVG3MM6RFhL12gT1hs5vEZufr6XbKA==",
"dev": true
},
"node_modules/lunr": {
"version": "2.3.9",
"resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz",
"integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==",
"dev": true
},
"node_modules/magic-string": {
"version": "0.30.7",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.7.tgz",
@@ -18435,6 +18454,18 @@
"node": ">=8"
}
},
"node_modules/shiki": {
"version": "0.14.7",
"resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.7.tgz",
"integrity": "sha512-dNPAPrxSc87ua2sKJ3H5dQ/6ZaY8RNnaAqK+t0eG7p0Soi2ydiqbGOTaZCqaYvA/uZYfS1LJnemt3Q+mSfcPCg==",
"dev": true,
"dependencies": {
"ansi-sequence-parser": "^1.1.0",
"jsonc-parser": "^3.2.0",
"vscode-oniguruma": "^1.7.0",
"vscode-textmate": "^8.0.0"
}
},
"node_modules/side-channel": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
@@ -19598,6 +19629,39 @@
"integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
"dev": true
},
"node_modules/typedoc": {
"version": "0.25.10",
"resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.25.10.tgz",
"integrity": "sha512-v10rtOFojrjW9og3T+6wAKeJaGMuojU87DXGZ33sfs+554wgPTRG+s07Ag1BjPZI85Y5QPVouPI63JQ6fcQM5w==",
"dev": true,
"dependencies": {
"lunr": "^2.3.9",
"marked": "^4.3.0",
"minimatch": "^9.0.3",
"shiki": "^0.14.7"
},
"bin": {
"typedoc": "bin/typedoc"
},
"engines": {
"node": ">= 16"
},
"peerDependencies": {
"typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x || 5.3.x"
}
},
"node_modules/typedoc/node_modules/marked": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz",
"integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==",
"dev": true,
"bin": {
"marked": "bin/marked.js"
},
"engines": {
"node": ">= 12"
}
},
"node_modules/typescript": {
"version": "5.3.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz",
@@ -20675,6 +20739,18 @@
"@esbuild/win32-x64": "0.19.12"
}
},
"node_modules/vscode-oniguruma": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz",
"integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==",
"dev": true
},
"node_modules/vscode-textmate": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz",
"integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==",
"dev": true
},
"node_modules/walker": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz",

View File

@@ -153,7 +153,8 @@
"wc-analyze": "wca **/*.element.ts --outFile dist-cms/custom-elements.json",
"generate:tsconfig": "node ./devops/tsconfig/index.js",
"generate:manifest": "node ./devops/build/create-umbraco-package.js",
"package:validate": "node ./devops/package/validate-exports.js"
"package:validate": "node ./devops/package/validate-exports.js",
"generate:api-docs": "typedoc --options typedoc.config.js"
},
"engines": {
"node": ">=20.9 <21",
@@ -226,6 +227,7 @@
"storybook": "^7.6.17",
"tiny-glob": "^0.2.9",
"tsc-alias": "^1.8.8",
"typedoc": "^0.25.10",
"typescript": "^5.3.3",
"typescript-json-schema": "^0.63.0",
"vite": "^5.1.1",

View File

@@ -1,17 +1,16 @@
import type { UmbAppContextConfig } from './app-context-config.interface.js';
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import { UmbContextBase } from '@umbraco-cms/backoffice/class-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
export class UmbAppContext extends UmbControllerBase {
export class UmbAppContext extends UmbContextBase<UmbAppContext> {
#serverUrl: string;
#backofficePath: string;
constructor(host: UmbControllerHost, config: UmbAppContextConfig) {
super(host);
super(host, UMB_APP_CONTEXT);
this.#serverUrl = config.serverUrl;
this.#backofficePath = config.backofficePath;
this.provideContext(UMB_APP_CONTEXT, this);
}
getBackofficePath() {

View File

@@ -127,7 +127,6 @@ export class RouterSlot<D = any, P = any> extends HTMLElement implements IRouter
*/
constructor() {
super();
this.addEventListener('router-slot:capture-parent', (e: any) => {
e.stopPropagation();
e.detail.parent = this;
@@ -248,9 +247,9 @@ export class RouterSlot<D = any, P = any> extends HTMLElement implements IRouter
this.listeners.push(
this.parent != null
? // Attach child router listeners
addListener<Event, RouterSlotEvent>(this.parent, 'changestate', this.render)
addListener<Event, RouterSlotEvent>(this.parent, 'changestate', this.render)
: // Add global listeners.
addListener<Event, GlobalRouterEvent>(GLOBAL_ROUTER_EVENTS_TARGET, 'changestate', this.render),
addListener<Event, GlobalRouterEvent>(GLOBAL_ROUTER_EVENTS_TARGET, 'changestate', this.render),
);
}

View File

@@ -14,12 +14,13 @@ export class UmbPropertyEditorUIBlockGridAreaTypePermissionElement
implements UmbPropertyEditorUiElement
{
@property({ type: Array })
public get value(): Array<UmbBlockGridTypeAreaTypePermission> {
return this._value;
}
public set value(value: Array<UmbBlockGridTypeAreaTypePermission>) {
this._value = value ?? [];
}
public get value(): Array<UmbBlockGridTypeAreaTypePermission> {
return this._value;
}
@state()
private _value: Array<UmbBlockGridTypeAreaTypePermission> = [];
@@ -151,7 +152,7 @@ export class UmbPropertyEditorUIBlockGridAreaTypePermissionElement
<umb-localize key="blockEditor_areaAllowedBlocksEmpty">
By default, all block types are allowed in an Area, Use this option to allow only selected types.
</umb-localize>
</small>`
</small>`
: nothing} `;
}

View File

@@ -24,19 +24,17 @@ export class UmbPropertyEditorUIBlockGridAreasConfigElement
#defaultAreaGridColumns: number = 12;
#valueOfAreaGridColumns?: number | null;
#workspaceModal: UmbModalRouteRegistrationController;
@property({ type: Array })
public get value(): Array<UmbBlockGridTypeAreaType> {
return this._value;
}
public set value(value: Array<UmbBlockGridTypeAreaType>) {
this._value = value ?? [];
}
public get value(): Array<UmbBlockGridTypeAreaType> {
return this._value;
}
@state()
private _value: Array<UmbBlockGridTypeAreaType> = [];
@property({ attribute: false })
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
const defaultAreaGridColumns = config?.getValueByAlias('defaultAreaGridColumns');
if (typeof defaultAreaGridColumns === 'number' && defaultAreaGridColumns > 0) {
@@ -59,7 +57,7 @@ export class UmbPropertyEditorUIBlockGridAreasConfigElement
constructor() {
super();
this.#workspaceModal = new UmbModalRouteRegistrationController(this, UMB_BLOCK_GRID_AREA_TYPE_WORKSPACE_MODAL)
new UmbModalRouteRegistrationController(this, UMB_BLOCK_GRID_AREA_TYPE_WORKSPACE_MODAL)
.addAdditionalPath('block-grid-area-type')
.onSetup(() => {
return { data: { entityType: 'block-grid-area-type', preset: {} }, modal: { size: 'large' } };

View File

@@ -13,7 +13,6 @@ export class UmbPropertyEditorUIBlockGridColumnSpanElement extends UmbLitElement
@state()
private _columnsArray = Array.from(Array(12).keys());
@property({ attribute: false })
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
const maxColumns = config?.getValueByAlias('maxColumns');
if (typeof maxColumns === 'number') {

View File

@@ -26,7 +26,6 @@ export class UmbPropertyEditorUIBlockGridElement extends UmbLitElement implement
settingsData: [],
};
@property({ attribute: false })
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
if (!config) return;
@@ -56,9 +55,6 @@ export class UmbPropertyEditorUIBlockGridElement extends UmbLitElement implement
private _layoutColumns?: number;
@property({ attribute: false })
public get value(): UmbBlockGridValueModel {
return this._value;
}
public set value(value: UmbBlockGridValueModel | undefined) {
const buildUpValue: Partial<UmbBlockGridValueModel> = value ? { ...value } : {};
buildUpValue.layout ??= {};
@@ -70,6 +66,9 @@ export class UmbPropertyEditorUIBlockGridElement extends UmbLitElement implement
this.#context.setContents(buildUpValue.contentData);
this.#context.setSettings(buildUpValue.settingsData);
}
public get value(): UmbBlockGridValueModel {
return this._value;
}
constructor() {
super();

View File

@@ -14,14 +14,13 @@ export class UmbPropertyEditorUIBlockGridGroupConfigurationElement
private _value: Array<UmbBlockGridTypeGroupType> = [];
@property({ type: Array })
public get value(): Array<UmbBlockGridTypeGroupType> {
return this._value;
}
public set value(value: Array<UmbBlockGridTypeGroupType>) {
this._value = value || [];
}
public get value(): Array<UmbBlockGridTypeGroupType> {
return this._value;
}
@property({ attribute: false })
public set config(config: UmbPropertyEditorConfigCollection | undefined) {}
#addGroup() {

View File

@@ -17,18 +17,18 @@ export class UmbPropertyEditorUIBlockGridLayoutStylesheetElement
private _value: Array<string> = [];
@property({ type: Array })
public get value(): Array<string> {
return this._value;
}
public set value(value: Array<string>) {
this._value = value || [];
}
public get value(): Array<string> {
return this._value;
}
@property({ attribute: false })
public set config(config: UmbPropertyEditorConfigCollection | undefined) {}
public config?: UmbPropertyEditorConfigCollection;
private _onChange(event: CustomEvent) {
this.value = (event.target as UmbInputStaticFileElement).selectedPaths;
this.value = (event.target as UmbInputStaticFileElement).selection;
this.dispatchEvent(new CustomEvent('property-value-change'));
}
@@ -37,7 +37,7 @@ export class UmbPropertyEditorUIBlockGridLayoutStylesheetElement
return html`
<umb-input-static-file
@change=${this._onChange}
.selectedIds=${this._value}
.selection=${this._value}
.min=${0}
.max=${1}></umb-input-static-file>
<br />

View File

@@ -51,9 +51,6 @@ export class UmbPropertyEditorUIBlockListElement extends UmbLitElement implement
};
@property({ attribute: false })
public get value(): UmbBlockListValueModel {
return this._value;
}
public set value(value: UmbBlockListValueModel | undefined) {
const buildUpValue: Partial<UmbBlockListValueModel> = value ? { ...value } : {};
buildUpValue.layout ??= {};
@@ -65,11 +62,13 @@ export class UmbPropertyEditorUIBlockListElement extends UmbLitElement implement
this.#managerContext.setContents(buildUpValue.contentData);
this.#managerContext.setSettings(buildUpValue.settingsData);
}
public get value(): UmbBlockListValueModel {
return this._value;
}
@state()
private _createButtonLabel = this.localize.term('content_createEmpty');
@property({ attribute: false })
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
if (!config) return;

View File

@@ -13,12 +13,12 @@ export class UmbInputBlockTypeElement<
BlockType extends UmbBlockTypeBaseModel = UmbBlockTypeBaseModel,
> extends UmbLitElement {
@property({ type: Array, attribute: false })
public get value() {
return this._items;
}
public set value(items) {
this._items = items ?? [];
}
public get value() {
return this._items;
}
@property({ type: String })
workspacePath?: string;
@@ -26,6 +26,7 @@ export class UmbInputBlockTypeElement<
@state()
private _items: Array<BlockType> = [];
// TODO: Seems no need to have these initially, then can be retrieved inside the `create` method. [NL]
#datasetContext?: UmbPropertyDatasetContext;
#filter: Array<UmbBlockTypeBaseModel> = [];

View File

@@ -3,10 +3,10 @@ import { UMB_AUTH_CONTEXT } from './auth.context.token.js';
import type { UmbOpenApiConfiguration } from './models/openApiConfiguration.js';
import { OpenAPI } from '@umbraco-cms/backoffice/external/backend-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import { UmbContextBase } from '@umbraco-cms/backoffice/class-api';
import { UmbBooleanState } from '@umbraco-cms/backoffice/observable-api';
export class UmbAuthContext extends UmbControllerBase {
export class UmbAuthContext extends UmbContextBase<UmbAuthContext> {
#isAuthorized = new UmbBooleanState<boolean>(false);
readonly isAuthorized = this.#isAuthorized.asObservable();
@@ -16,13 +16,12 @@ export class UmbAuthContext extends UmbControllerBase {
#authFlow;
constructor(host: UmbControllerHost, serverUrl: string, backofficePath: string, isBypassed: boolean) {
super(host);
super(host, UMB_AUTH_CONTEXT);
this.#isBypassed = isBypassed;
this.#serverUrl = serverUrl;
this.#backofficePath = backofficePath;
this.#authFlow = new UmbAuthFlow(serverUrl, this.#getRedirectUrl());
this.provideContext(UMB_AUTH_CONTEXT, this);
}
/**

View File

@@ -39,15 +39,15 @@ export class UmbFieldDropdownListElement extends UmbLitElement {
private _value: FieldPickerValue | undefined;
@property({ type: Object })
public get value(): FieldPickerValue | undefined {
return this._value;
}
public set value(val: FieldPickerValue | undefined) {
const oldVal = this._value;
this._value = val;
this.requestUpdate('value', oldVal);
this.dispatchEvent(new UmbChangeEvent());
}
public get value(): FieldPickerValue | undefined {
return this._value;
}
@state()
private _type?: FieldType;
@@ -168,7 +168,7 @@ export class UmbFieldDropdownListElement extends UmbLitElement {
display-value=${this.localize.term('content_mediatype')}>
<strong> ${this.localize.term('content_mediatype')} </strong>
${this.localize.term('defaultdialogs_treepicker')}
</uui-combobox-list-option>`
</uui-combobox-list-option>`
: nothing}
</uui-combobox-list>
</uui-combobox>

View File

@@ -1,8 +1,9 @@
import { html, customElement, property } from '@umbraco-cms/backoffice/external/lit';
import type { UUIColorSwatchesEvent } from '@umbraco-cms/backoffice/external/uui';
import { html, customElement, property, map, nothing } from '@umbraco-cms/backoffice/external/lit';
import { FormControlMixin } from '@umbraco-cms/backoffice/external/uui';
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type { UmbSwatchDetails } from '@umbraco-cms/backoffice/models';
import type { UUIColorSwatchesEvent } from '@umbraco-cms/backoffice/external/uui';
/*
* This wraps the UUI library uui-color-swatches component
@@ -16,35 +17,35 @@ export class UmbInputColorElement extends FormControlMixin(UmbLitElement) {
@property({ type: Array })
swatches?: UmbSwatchDetails[];
constructor() {
super();
}
protected getFormElement() {
return undefined;
}
private _onChange(e: UUIColorSwatchesEvent) {
e.stopPropagation();
super.value = e.target.value;
this.dispatchEvent(new CustomEvent('change'));
#onChange(event: UUIColorSwatchesEvent) {
event.stopPropagation();
super.value = event.target.value;
this.dispatchEvent(new UmbChangeEvent());
}
render() {
return html`
<uui-color-swatches @change="${this._onChange}" label="Color picker" value=${this.value ?? ''}
>${this._renderColors()}</uui-color-swatches
>
<uui-color-swatches label="Color picker" value="#${this.value ?? ''}" @change=${this.#onChange}>
${this.#renderColors()}
</uui-color-swatches>
`;
}
private _renderColors() {
return html`${this.swatches?.map((swatch) => {
return html`<uui-color-swatch
label="${swatch.label}"
value="${swatch.value}"
.showLabel=${this.showLabels}></uui-color-swatch>`;
})}`;
#renderColors() {
if (!this.swatches) return nothing;
return map(
this.swatches,
(swatch) => html`
<uui-color-swatch
label="${swatch.label}"
value="#${swatch.value}"
.showLabel=${this.showLabels}></uui-color-swatch>
`,
);
}
}

View File

@@ -1,7 +1,8 @@
import { css, html, customElement, property, query } from '@umbraco-cms/backoffice/external/lit';
import type { UUISelectEvent } from '@umbraco-cms/backoffice/external/uui';
import { FormControlMixin } from '@umbraco-cms/backoffice/external/uui';
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type { UUISelectEvent } from '@umbraco-cms/backoffice/external/uui';
@customElement('umb-input-dropdown-list')
export class UmbInputDropdownListElement extends FormControlMixin(UmbLitElement) {
@@ -25,7 +26,7 @@ export class UmbInputDropdownListElement extends FormControlMixin(UmbLitElement)
#onChange(e: UUISelectEvent) {
e.stopPropagation();
if (e.target.value) this.value = e.target.value;
this.dispatchEvent(new CustomEvent('change', { bubbles: true, composed: true }));
this.dispatchEvent(new UmbChangeEvent());
}
render() {

View File

@@ -1,7 +1,7 @@
import { css, html, customElement, property } from '@umbraco-cms/backoffice/external/lit';
import type { UUIColorPickerChangeEvent } from '@umbraco-cms/backoffice/external/uui';
import { html, customElement, property } from '@umbraco-cms/backoffice/external/lit';
import { FormControlMixin } from '@umbraco-cms/backoffice/external/uui';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type { UUIColorPickerChangeEvent } from '@umbraco-cms/backoffice/external/uui';
@customElement('umb-input-eye-dropper')
export class UmbInputEyeDropperElement extends FormControlMixin(UmbLitElement) {
@@ -9,7 +9,7 @@ export class UmbInputEyeDropperElement extends FormControlMixin(UmbLitElement) {
return undefined;
}
private _onChange(e: UUIColorPickerChangeEvent) {
#onChange(e: UUIColorPickerChangeEvent) {
e.stopPropagation();
super.value = e.target.value;
this.dispatchEvent(new CustomEvent('change'));
@@ -18,17 +18,19 @@ export class UmbInputEyeDropperElement extends FormControlMixin(UmbLitElement) {
@property({ type: Boolean })
opacity = false;
@property()
@property({ type: Array })
swatches: string[] = [];
//TODO if empty swatches, the color picker still shows the area where they are supposed to be rendered.
//TODO if empty swatches, the color picker still shows the area where they are supposed to be rendered.
// BTW in the old backoffice "palette" seemed to be true/false setting, but here its an array.
render() {
return html`<uui-color-picker
label="Eye dropper"
@change="${this._onChange}"
.opacity="${this.opacity}"
.swatches="${this.swatches}"></uui-color-picker>`;
.opacity=${this.opacity}
.swatches=${this.swatches}
.value=${this.value as string}
@change=${this.#onChange}></uui-color-picker>`;
}
}

View File

@@ -22,11 +22,17 @@ export class UmbInputMultiUrlElement extends FormControlMixin(UmbLitElement) {
public set alias(value: string | undefined) {
this.myModalRegistration.setUniquePathValue('propertyAlias', value);
}
public get alias(): string | undefined {
return this.myModalRegistration.getUniquePathValue('propertyAlias');
}
@property()
public set variantId(value: string | UmbVariantId | undefined) {
this.myModalRegistration.setUniquePathValue('variantId', value?.toString());
}
public get variantId(): string | undefined {
return this.myModalRegistration.getUniquePathValue('variantId');
}
/**
* This is a minimum amount of selected items in this input.
@@ -91,8 +97,7 @@ export class UmbInputMultiUrlElement extends FormControlMixin(UmbLitElement) {
this._urls = [...data]; // Unfreeze data coming from State, so we can manipulate it.
super.value = this._urls.map((x) => x.url).join(',');
}
get urls() {
get urls(): Array<UmbLinkPickerLink> {
return this._urls;
}

View File

@@ -54,9 +54,8 @@ export class UmbInputNumberRangeElement extends FormControlMixin(UmbLitElement)
this.maxValue = getNumberOrUndefined(splittedValue[1]);
}
}
constructor() {
super();
public get value(): string {
return this.minValue || this.maxValue ? (this.minValue || '') + ',' + (this.maxValue || '') : '';
}
protected getFormElement() {

View File

@@ -1,52 +1,52 @@
import { css, html, nothing, repeat, customElement, property } from '@umbraco-cms/backoffice/external/lit';
import type { UUIBooleanInputEvent } from '@umbraco-cms/backoffice/external/uui';
import { FormControlMixin } from '@umbraco-cms/backoffice/external/uui';
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type { UUIBooleanInputEvent } from '@umbraco-cms/backoffice/external/uui';
@customElement('umb-input-radio-button-list')
export class UmbInputRadioButtonListElement extends FormControlMixin(UmbLitElement) {
/**
* List of items.
*/
@property()
public list: Array<{ key: string; sortOrder: number; value: string }> = [];
#selected = '';
public get selected(): string {
return this.#selected;
}
public set selected(key: string) {
this.#selected = key;
super.value = key;
}
#value: string = '';
@property()
public set value(key: string) {
if (key !== this._value) {
this.selected = key;
}
public set value(value: string) {
this.#value = value;
}
public get value(): string {
return this.#value;
}
@property({ type: Array })
public list: Array<{ label: string; value: string }> = [];
protected getFormElement() {
return undefined;
}
#setSelection(e: UUIBooleanInputEvent) {
e.stopPropagation();
if (e.target.value) this.selected = e.target.value;
this.dispatchEvent(new CustomEvent('change', { bubbles: true, composed: true }));
#onChange(event: UUIBooleanInputEvent) {
event.stopPropagation();
this.value = event.target.value;
this.dispatchEvent(new UmbChangeEvent());
}
render() {
if (!this.list) return nothing;
return html`<uui-radio-group .value=${this.value} @change=${this.#setSelection}>
${repeat(this.list, (item) => item, this.renderRadioButton)}
</uui-radio-group>`;
return html`
<uui-radio-group .value=${this.value} @change=${this.#onChange}>
${repeat(
this.list,
(item) => item,
(item) => this.#renderRadioButton(item),
)}
</uui-radio-group>
`;
}
renderRadioButton(item: { key: string; sortOrder: number; value: string }) {
return html`<uui-radio value="${item.value}" label="${item.value}"></uui-radio>`;
#renderRadioButton(item: (typeof this.list)[0]) {
return html`<uui-radio value="${item.value}" label="${item.label}"></uui-radio>`;
}
static styles = [

View File

@@ -13,21 +13,9 @@ type Story = StoryObj<UmbInputRadioButtonListElement>;
export const Overview: Story = {
args: {
list: [
{
key: '1',
sortOrder: 0,
value: 'One',
},
{
key: '2',
sortOrder: 1,
value: 'Two',
},
{
key: '3',
sortOrder: 2,
value: 'Three',
},
{ label: 'One', value: '1' },
{ label: 'Two', value: '2' },
{ label: 'Three', value: '3' },
],
},
};
@@ -35,45 +23,20 @@ export const Overview: Story = {
export const WithSelectedValue: Story = {
args: {
list: [
{
key: '1',
sortOrder: 0,
value: 'One',
},
{
key: '2',
sortOrder: 1,
value: 'Two',
},
{
key: '3',
sortOrder: 2,
value: 'Three',
},
{ label: 'One', value: '1' },
{ label: 'Two', value: '2' },
{ label: 'Three', value: '3' },
],
selected: '2',
value: 'Two',
value: '2',
},
};
export const SortOrder: Story = {
args: {
list: [
{
key: '1',
sortOrder: 4,
value: 'One',
},
{
key: '2',
sortOrder: 1,
value: 'Two',
},
{
key: '3',
sortOrder: 2,
value: 'Three',
},
{ label: 'One', value: '1' },
{ label: 'Two', value: '2' },
{ label: 'Three', value: '3' },
],
},
};

View File

@@ -1,7 +1,7 @@
import { css, html, customElement, property } from '@umbraco-cms/backoffice/external/lit';
import type { UUISliderEvent } from '@umbraco-cms/backoffice/external/uui';
import { html, customElement, property } from '@umbraco-cms/backoffice/external/lit';
import { FormControlMixin } from '@umbraco-cms/backoffice/external/uui';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type { UUISliderEvent } from '@umbraco-cms/backoffice/external/uui';
@customElement('umb-input-slider')
export class UmbInputSliderElement extends FormControlMixin(UmbLitElement) {
@@ -15,10 +15,10 @@ export class UmbInputSliderElement extends FormControlMixin(UmbLitElement) {
step = 1;
@property({ type: Number })
initVal1 = 0;
valueLow = 0;
@property({ type: Number })
initVal2 = 0;
valueHigh = 0;
@property({ type: Boolean, attribute: 'enable-range' })
enableRange = false;
@@ -34,8 +34,7 @@ export class UmbInputSliderElement extends FormControlMixin(UmbLitElement) {
}
render() {
if (this.enableRange) return this.#renderRangeSlider();
else return this.#renderSlider();
return this.enableRange ? this.#renderRangeSlider() : this.#renderSlider();
}
#renderSlider() {
@@ -43,7 +42,7 @@ export class UmbInputSliderElement extends FormControlMixin(UmbLitElement) {
.min="${this.min}"
.max="${this.max}"
.step="${this.step}"
.value="${this.initVal1.toString()}"
.value="${this.valueLow.toString()}"
@change="${this.#onChange}"></uui-slider>`;
}
#renderRangeSlider() {
@@ -51,8 +50,7 @@ export class UmbInputSliderElement extends FormControlMixin(UmbLitElement) {
.min="${this.min}"
.max="${this.max}"
.step="${this.step}"
.valueLow="${this.initVal1}"
.valueHigh="${this.initVal2}"
.value="${this.valueLow},${this.valueHigh}"
@change="${this.#onChange}"></uui-range-slider>`;
}
}

View File

@@ -15,7 +15,7 @@ export const Overview: Story = {
min: 0,
max: 100,
step: 10,
initVal1: 20,
valueLow: 20,
},
};
@@ -24,8 +24,8 @@ export const WithRange: Story = {
min: 0,
max: 100,
step: 10,
initVal1: 20,
initVal2: 80,
valueLow: 20,
valueHigh: 80,
enableRange: true,
},
};
@@ -35,7 +35,7 @@ export const WithSmallStep: Story = {
min: 0,
max: 5,
step: 1,
initVal1: 4,
valueLow: 4,
},
};
@@ -44,6 +44,6 @@ export const WithLargeMinMax: Story = {
min: 0,
max: 100,
step: 1,
initVal1: 86,
valueLow: 86,
},
};

View File

@@ -32,10 +32,6 @@ export class UmbInputToggleElement extends FormControlMixin(UmbLitElement) {
return undefined;
}
constructor() {
super();
}
connectedCallback(): void {
super.connectedCallback();
this.#updateLabel();

View File

@@ -126,12 +126,12 @@ export class UmbInputMultipleTextStringElement extends FormControlMixin(UmbLitEl
// How do we handle this?
/*
@property()
public get value() {
throw new Error(`${this} does not support to get the value directly. Use items instead.`);
}
public set value(value: FormDataEntryValue | FormData) {
throw new Error(`${this} does not support to set the value directly. Use items instead.`);
}
public get value() {
throw new Error(`${this} does not support to get the value directly. Use items instead.`);
}
*/
#onAdd() {

View File

@@ -12,16 +12,17 @@ export class UmbEntityActionElement<
> extends UmbLitElement {
#api?: ApiType;
// TODO: Do these need to be properties? [NL]
@property({ type: String })
entityType?: string | null;
// TODO: Do these need to be properties? [NL]
@property({ type: String })
public unique?: string | null;
@property({ attribute: false })
public manifest?: ManifestEntityAction<MetaType>;
@property({ attribute: false })
public set api(api: ApiType | undefined) {
this.#api = api;

View File

@@ -38,21 +38,21 @@ export abstract class UmbModalBaseElement<
#modalContext?: UmbModalContext<ModalDataType, ModalValueType> | undefined;
@property({ attribute: false })
public get data(): ModalDataType | undefined {
return this._data;
}
public set data(value: ModalDataType | undefined) {
this._data = value;
}
public get data(): ModalDataType | undefined {
return this._data;
}
private _data?: ModalDataType | undefined;
@property({ attribute: false })
public get value(): ModalValueType {
return this.#value;
}
public set value(value: ModalValueType) {
this.#modalContext?.setValue(value);
}
public get value(): ModalValueType {
return this.#value;
}
public updateValue(partialValue: Partial<ModalValueType>) {
this.#modalContext?.updateValue(partialValue);

View File

@@ -1,7 +1,7 @@
import './component/modal.element.js';
export * from './context/index.js';
export * from './route-registration/modal-route-registration.js';
export * from './route-registration/modal-route-registration.interface.js';
export * from './route-registration/modal-route-registration.controller.js';
export * from './token/index.js';
export * from './types.js';

View File

@@ -1,15 +1,29 @@
import type { UmbModalToken } from '../token/index.js';
import { UmbModalRouteRegistration } from './modal-route-registration.js';
import { UMB_ROUTE_CONTEXT } from '@umbraco-cms/backoffice/router';
import type { UmbController, UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import type { UmbModalConfig, UmbModalContext, UmbModalManagerContext, UmbModalRouteRegistration } from '../index.js';
import { type Params, type IRouterSlot, UMB_ROUTE_CONTEXT, encodeFolderName } from '@umbraco-cms/backoffice/router';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api';
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import { UmbId } from '@umbraco-cms/backoffice/id';
export class UmbModalRouteRegistrationController<D extends object = object, R = any>
extends UmbModalRouteRegistration<D, R>
implements UmbController
export type UmbModalRouteBuilder = (params: { [key: string]: string | number } | null) => string;
export type UmbModalRouteSetupReturn<UmbModalTokenData, UmbModalTokenValue> = UmbModalTokenValue extends undefined
? {
modal?: UmbModalConfig;
data: UmbModalTokenData;
value?: UmbModalTokenValue;
}
: {
modal?: UmbModalConfig;
data: UmbModalTokenData;
value: UmbModalTokenValue;
};
export class UmbModalRouteRegistrationController<UmbModalTokenData extends object = object, UmbModalTokenValue = any>
extends UmbControllerBase
implements UmbModalRouteRegistration<UmbModalTokenData, UmbModalTokenValue>
{
//
#host;
#init;
#contextConsumer;
@@ -17,14 +31,24 @@ export class UmbModalRouteRegistrationController<D extends object = object, R =
#uniquePaths: Map<string, string | undefined> = new Map();
#routeContext?: typeof UMB_ROUTE_CONTEXT.TYPE;
#modalRegistration?: UmbModalRouteRegistration;
#modalRegistrationContext?: typeof UMB_ROUTE_CONTEXT.TYPE;
public get controllerAlias() {
return this.alias.toString();
}
protected getControllerHost() {
return this.#host;
}
#key: string;
#path?: string;
#modalAlias: UmbModalToken<UmbModalTokenData, UmbModalTokenValue> | string;
#onSetupCallback?: (
routingInfo: Params,
) =>
| Promise<UmbModalRouteSetupReturn<UmbModalTokenData, UmbModalTokenValue> | false>
| UmbModalRouteSetupReturn<UmbModalTokenData, UmbModalTokenValue>
| false;
#onSubmitCallback?: (data: UmbModalTokenValue) => void;
#onRejectCallback?: () => void;
#modalContext: UmbModalContext<UmbModalTokenData, UmbModalTokenValue> | undefined;
#routeBuilder?: UmbModalRouteBuilder;
#urlBuilderCallback: ((urlBuilder: UmbModalRouteBuilder) => void) | undefined;
/**
* Creates an instance of UmbModalRouteRegistrationController.
@@ -32,11 +56,13 @@ export class UmbModalRouteRegistrationController<D extends object = object, R =
* @param {UmbModalToken} alias - The alias of the modal, this is used to identify the modal.
* @memberof UmbModalRouteRegistrationController
*/
constructor(host: UmbControllerHost, alias: UmbModalToken<D, R> | string) {
super(alias, null);
this.#host = host;
constructor(host: UmbControllerHost, alias: UmbModalToken<UmbModalTokenData, UmbModalTokenValue> | string) {
super(host, alias.toString());
this.#key = UmbId.new();
this.#modalAlias = alias;
//this.#path = path;
this.#contextConsumer = new UmbContextConsumerController(host, UMB_ROUTE_CONTEXT, (_routeContext) => {
this.#contextConsumer = new UmbContextConsumerController(this, UMB_ROUTE_CONTEXT, (_routeContext) => {
this.#routeContext = _routeContext;
this.#registerModal();
});
@@ -118,6 +144,9 @@ export class UmbModalRouteRegistrationController<D extends object = object, R =
this.#uniquePaths.set(identifier, value);
this.#registerModal();
}
getUniquePathValue(identifier: string): string | undefined {
return this.#uniquePaths.get(identifier);
}
async #registerModal() {
await this.#init;
@@ -128,7 +157,6 @@ export class UmbModalRouteRegistrationController<D extends object = object, R =
// Check if there is any undefined values of unique map:
if (pathParts.some((value) => value === undefined)) {
this.#unregisterModal();
return;
}
if (this.#additionalPath) {
@@ -138,44 +166,147 @@ export class UmbModalRouteRegistrationController<D extends object = object, R =
const newPath = pathParts.join('/') ?? '';
//if no changes then break out:
if (this.path === newPath) {
// if no changes then break out:
// We test for both path and context changes [NL]
if (this.path === newPath && this.#modalRegistrationContext === this.#routeContext) {
return;
}
// Clean up if it already exists:
this.#unregisterModal();
// Make this the path of the modal registration:
this._setPath(newPath);
this.#modalRegistration = this.#routeContext.registerModal(this);
this.#routeContext.registerModal(this);
// Store which context we used and use this as 'if registered', so we can know if it changed.
this.#modalRegistrationContext = this.#routeContext;
}
async #unregisterModal() {
if (!this.#routeContext) return;
if (this.#modalRegistration) {
this.#routeContext.unregisterModal(this.#modalRegistration);
this.#modalRegistration = undefined;
if (this.#modalRegistrationContext) {
this.#modalRegistrationContext.unregisterModal(this);
this.#modalRegistrationContext = undefined;
}
}
hostConnected() {
if (!this.#modalRegistration) {
super.hostConnected();
if (!this.#modalRegistrationContext) {
this.#registerModal();
}
}
hostDisconnected(): void {
if (this.#modalRegistration) {
this.#routeContext?.unregisterModal(this.#modalRegistration);
this.#modalRegistration = undefined;
super.hostDisconnected();
if (this.#modalRegistrationContext) {
this.#modalRegistrationContext.unregisterModal(this);
this.#modalRegistrationContext = undefined;
}
}
public get key() {
return this.#key;
}
public get alias() {
return this.#modalAlias;
}
public generateModalPath() {
return `modal/${encodeFolderName(this.alias.toString())}${this.path && this.path !== '' ? `/${this.path}` : ''}`;
}
public get path() {
return this.#path;
}
protected _setPath(path: string | undefined) {
this.#path = path;
}
/**
* Returns true if the modal is currently active.
*/
public get active() {
return !!this.#modalContext;
}
public open(params: { [key: string]: string | number }, prepend?: string) {
if (this.active) return;
window.history.pushState({}, '', this.#routeBuilder?.(params) + (prepend ? `${prepend}` : ''));
}
/**
* Returns the modal handler if the modal is currently active. Otherwise its undefined.
*/
public get modalContext() {
return this.#modalContext;
}
public observeRouteBuilder(callback: (urlBuilder: UmbModalRouteBuilder) => void) {
this.#urlBuilderCallback = callback;
return this;
}
public _internal_setRouteBuilder(urlBuilder: UmbModalRouteBuilder) {
this.#routeBuilder = urlBuilder;
this.#urlBuilderCallback?.(urlBuilder);
}
public onSetup(
callback: (
routingInfo: Params,
) =>
| Promise<UmbModalRouteSetupReturn<UmbModalTokenData, UmbModalTokenValue> | false>
| UmbModalRouteSetupReturn<UmbModalTokenData, UmbModalTokenValue>
| false,
) {
this.#onSetupCallback = callback;
return this;
}
public onSubmit(callback: (value: UmbModalTokenValue) => void) {
this.#onSubmitCallback = callback;
return this;
}
public onReject(callback: () => void) {
this.#onRejectCallback = callback;
return this;
}
#onSubmit = (data: UmbModalTokenValue) => {
this.#onSubmitCallback?.(data);
this.#modalContext = undefined;
};
#onReject = () => {
this.#onRejectCallback?.();
this.#modalContext = undefined;
};
async routeSetup(router: IRouterSlot, modalManagerContext: UmbModalManagerContext, params: Params) {
// If already open, don't do anything:
if (this.active) return;
const modalData = this.#onSetupCallback ? await this.#onSetupCallback(params) : undefined;
if (modalData !== false) {
const args = {
modal: {},
...modalData,
router,
};
args.modal.key = this.#key;
this.#modalContext = modalManagerContext.open(this, this.#modalAlias, args);
this.#modalContext.onSubmit().then(this.#onSubmit, this.#onReject);
return this.#modalContext;
}
return;
}
public destroy(): void {
this.#host?.removeController(this);
this.#host = undefined as any;
super.destroy();
this.#contextConsumer.destroy();
this.#modalRegistration = undefined;
this.#modalRegistrationContext = undefined;
this.#uniquePaths = undefined as any;
this.#routeContext = undefined;
}

View File

@@ -0,0 +1,22 @@
import type { UmbModalManagerContext } from '../context/modal-manager.context.js';
import type { UmbModalContext, UmbModalRouteBuilder } from '../index.js';
import type { UmbModalToken } from '../token/modal-token.js';
import type { IRouterSlot, Params } from '@umbraco-cms/backoffice/router';
export interface UmbModalRouteRegistration<UmbModalTokenData extends object = object, UmbModalTokenValue = any> {
key: string;
alias: UmbModalToken<UmbModalTokenData, UmbModalTokenValue> | string;
generateModalPath(): string;
path: string | undefined;
open(params: { [key: string]: string | number }, prepend?: string): void;
routeSetup(
router: IRouterSlot,
modalManagerContext: UmbModalManagerContext,
params: Params,
): Promise<undefined | UmbModalContext<UmbModalTokenData, UmbModalTokenValue>>;
_internal_setRouteBuilder(builder: UmbModalRouteBuilder): void;
}

View File

@@ -1,151 +0,0 @@
import type { UmbModalContext } from '../context/modal.context.js';
import type { UmbModalConfig, UmbModalManagerContext } from '../context/modal-manager.context.js';
import type { UmbModalToken } from '../token/modal-token.js';
import type { IRouterSlot } from '@umbraco-cms/backoffice/external/router-slot';
import { encodeFolderName } from '@umbraco-cms/backoffice/router';
import { UmbId } from '@umbraco-cms/backoffice/id';
import type { Params } from '@umbraco-cms/backoffice/router';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
export type UmbModalRouteBuilder = (params: { [key: string]: string | number } | null) => string;
export type UmbModalRouteSetupReturn<UmbModalTokenData, UmbModalTokenValue> = UmbModalTokenValue extends undefined
? {
modal?: UmbModalConfig;
data: UmbModalTokenData;
value?: UmbModalTokenValue;
}
: {
modal?: UmbModalConfig;
data: UmbModalTokenData;
value: UmbModalTokenValue;
};
export abstract class UmbModalRouteRegistration<UmbModalTokenData extends object = object, UmbModalTokenValue = any> {
#key: string;
#path: string | null;
#modalAlias: UmbModalToken<UmbModalTokenData, UmbModalTokenValue> | string;
#onSetupCallback?: (
routingInfo: Params,
) =>
| Promise<UmbModalRouteSetupReturn<UmbModalTokenData, UmbModalTokenValue> | false>
| UmbModalRouteSetupReturn<UmbModalTokenData, UmbModalTokenValue>
| false;
#onSubmitCallback?: (data: UmbModalTokenValue) => void;
#onRejectCallback?: () => void;
#modalContext: UmbModalContext<UmbModalTokenData, UmbModalTokenValue> | undefined;
#routeBuilder?: UmbModalRouteBuilder;
#urlBuilderCallback: ((urlBuilder: UmbModalRouteBuilder) => void) | undefined;
/**
* Should returns the host element of the modal, but this simple registration is not capable of that. So it has to be overwritten by a more specific implementation.
*/
protected abstract getControllerHost(): UmbControllerHost;
// Notice i removed the key in the transferring to this class.
constructor(modalAlias: UmbModalToken<UmbModalTokenData, UmbModalTokenValue> | string, path: string | null = null) {
this.#key = UmbId.new();
this.#modalAlias = modalAlias;
this.#path = path;
}
public get key() {
return this.#key;
}
public get alias() {
return this.#modalAlias;
}
public generateModalPath() {
return `modal/${encodeFolderName(this.alias.toString())}${this.path && this.path !== '' ? `/${this.path}` : ''}`;
}
public get path() {
return this.#path;
}
protected _setPath(path: string | null) {
this.#path = path;
}
/**
* Returns true if the modal is currently active.
*/
public get active() {
return !!this.#modalContext;
}
public open(params: { [key: string]: string | number }, prepend?: string) {
if (this.active) return;
window.history.pushState({}, '', this.#routeBuilder?.(params) + (prepend ? `${prepend}` : ''));
}
/**
* Returns the modal handler if the modal is currently active. Otherwise its undefined.
*/
public get modalContext() {
return this.#modalContext;
}
public observeRouteBuilder(callback: (urlBuilder: UmbModalRouteBuilder) => void) {
this.#urlBuilderCallback = callback;
return this;
}
public _internal_setRouteBuilder(urlBuilder: UmbModalRouteBuilder) {
this.#routeBuilder = urlBuilder;
this.#urlBuilderCallback?.(urlBuilder);
}
public onSetup(
callback: (
routingInfo: Params,
) =>
| Promise<UmbModalRouteSetupReturn<UmbModalTokenData, UmbModalTokenValue> | false>
| UmbModalRouteSetupReturn<UmbModalTokenData, UmbModalTokenValue>
| false,
) {
this.#onSetupCallback = callback;
return this;
}
public onSubmit(callback: (value: UmbModalTokenValue) => void) {
this.#onSubmitCallback = callback;
return this;
}
public onReject(callback: () => void) {
this.#onRejectCallback = callback;
return this;
}
#onSubmit = (data: UmbModalTokenValue) => {
this.#onSubmitCallback?.(data);
this.#modalContext = undefined;
};
#onReject = () => {
this.#onRejectCallback?.();
this.#modalContext = undefined;
};
async routeSetup(router: IRouterSlot, modalManagerContext: UmbModalManagerContext, params: Params) {
// If already open, don't do anything:
if (this.active) return;
const modalData = this.#onSetupCallback ? await this.#onSetupCallback(params) : undefined;
if (modalData !== false) {
const args = {
modal: {},
...modalData,
router,
};
args.modal.key = this.#key;
this.#modalContext = modalManagerContext.open(this.getControllerHost(), this.#modalAlias, args);
this.#modalContext.onSubmit().then(this.#onSubmit, this.#onReject);
return this.#modalContext;
}
return null;
}
}

View File

@@ -21,7 +21,6 @@ export class UmbPropertyActionElement<
@property({ attribute: false })
public manifest?: ManifestPropertyActionDefaultKind<MetaType>;
@property({ attribute: false })
public set api(api: ApiType | undefined) {
this.#api = api;

View File

@@ -18,7 +18,13 @@ export const manifest: ManifestPropertyEditorSchema = {
alias: 'storageType',
label: 'Storage Type',
description: '',
propertyEditorUiAlias: 'Umb.PropertyEditorUi.Tags.StorageType',
propertyEditorUiAlias: 'Umb.PropertyEditorUi.Dropdown',
config: [
{
alias: 'items',
value: ['Csv', 'Json'],
},
],
},
],
defaultData: [

View File

@@ -1,64 +1,64 @@
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
import { css, html, nothing, repeat, customElement, property } from '@umbraco-cms/backoffice/external/lit';
import type { UUIBooleanInputEvent } from '@umbraco-cms/backoffice/external/uui';
import { FormControlMixin } from '@umbraco-cms/backoffice/external/uui';
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type { UUIBooleanInputEvent } from '@umbraco-cms/backoffice/external/uui';
@customElement('umb-input-checkbox-list')
export class UmbInputCheckboxListElement extends FormControlMixin(UmbLitElement) {
/**
* List of items.
*/
// TODO: Could this use a type that we export to ensure TS failure, or hook this up with a type coming from backend?
// TODO: Could this use a type that we export to ensure TS failure, or hook this up with a type coming from backend?
@property({ attribute: false })
public list: Array<{ key: string; checked: boolean; value: string }> = [];
public list: Array<{ label: string; value: string; checked: boolean }> = [];
#selected: Array<string> = [];
public get selected(): Array<string> {
return this.#selected;
#selection: Array<string> = [];
@property({ type: Array })
public set selection(values: Array<string>) {
this.#selection = values;
super.value = values.join(',');
}
public set selected(keys: Array<string>) {
this.#selected = keys;
super.value = keys.join(',');
public get selection(): Array<string> {
return this.#selection;
}
@property()
public set value(keysString: string) {
if (keysString !== this._value) {
this.selected = keysString.split(/[ ,]+/);
}
public set value(value: string) {
this.selection = value.split(',');
}
protected getFormElement() {
return undefined;
}
#setSelection(e: UUIBooleanInputEvent) {
#onChange(e: UUIBooleanInputEvent) {
e.stopPropagation();
if (e.target.checked) this.selected = [...this.selected, e.target.value];
else this.#removeFromSelection(this.selected.findIndex((key) => e.target.value === key));
if (e.target.checked) this.selection = [...this.selection, e.target.value];
else this.#removeFromSelection(this.selection.findIndex((value) => e.target.value === value));
this.dispatchEvent(new UmbChangeEvent());
}
#removeFromSelection(index: number) {
if (index == -1) return;
const keys = [...this.selected];
keys.splice(index, 1);
this.selected = keys;
const values = [...this.selection];
values.splice(index, 1);
this.selection = values;
}
render() {
if (!this.list) return nothing;
return html`<form>
<uui-form @change="${this.#setSelection}">
${repeat(this.list, (item) => item.key, this.renderCheckbox)}
<uui-form @change="${this.#onChange}">
${repeat(
this.list,
(item) => item.value,
(item) => this.#renderCheckbox(item),
)}
</uui-form>
</form>`;
}
renderCheckbox(item: { key: string; checked: boolean; value: string }) {
return html`<uui-checkbox value="${item.value}" label="${item.value}" ?checked="${item.checked}"></uui-checkbox>`;
#renderCheckbox(item: (typeof this.list)[0]) {
return html`<uui-checkbox ?checked=${item.checked} label=${item.label} value=${item.value}></uui-checkbox>`;
}
static styles = [

View File

@@ -14,13 +14,13 @@ export const Overview: Story = {
args: {
list: [
{
key: 'isAwesome',
value: 'Umbraco is awesome?',
label: 'Umbraco is awesome?',
value: 'isAwesome',
checked: true,
},
{
key: 'attendingCodeGarden',
value: 'Attending CodeGarden?',
label: 'Attending CodeGarden?',
value: 'attendingCodeGarden',
checked: false,
},
],

View File

@@ -1,9 +1,11 @@
import type { UmbInputCheckboxListElement } from './input-checkbox-list/input-checkbox-list.element.js';
import './input-checkbox-list/input-checkbox-list.element.js';
import { html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit';
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbPropertyValueChangeEvent } from '@umbraco-cms/backoffice/property-editor';
import type { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor';
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
import './input-checkbox-list/input-checkbox-list.element.js';
/**
* @element umb-property-editor-ui-checkbox-list
@@ -12,48 +14,34 @@ import type { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/
export class UmbPropertyEditorUICheckboxListElement extends UmbLitElement implements UmbPropertyEditorUiElement {
#value: Array<string> = [];
@property({ type: Array })
public get value(): Array<string> {
return this.#value;
}
public set value(value: Array<string>) {
this.#value = value ?? [];
}
public get value(): Array<string> {
return this.#value;
}
@property({ attribute: false })
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
if (!config) return;
const listData: Record<number, { value: string; sortOrder: number }> | undefined = config.getValueByAlias('items');
if (!listData) return;
// formatting the items in the dictionary into an array
const sortedItems = [];
const values = Object.values<{ value: string; sortOrder: number }>(listData);
const keys = Object.keys(listData);
for (let i = 0; i < values.length; i++) {
sortedItems.push({ key: keys[i], sortOrder: values[i].sortOrder, value: values[i].value });
}
// ensure the items are sorted by the provided sort order
sortedItems.sort((a, b) => {
return a.sortOrder > b.sortOrder ? 1 : b.sortOrder > a.sortOrder ? -1 : 0;
});
this._list = sortedItems.map((x) => ({ key: x.key, checked: this.#value.includes(x.value), value: x.value }));
const listData: string[] | undefined = config?.getValueByAlias('items');
this._list = listData?.map((item) => ({ label: item, value: item, checked: this.#value.includes(item) })) ?? [];
}
@state()
private _list: Array<{ key: string; checked: boolean; value: string }> = [];
private _list: UmbInputCheckboxListElement['list'] = [];
#onChange(event: CustomEvent) {
this.value = (event.target as UmbInputCheckboxListElement).selected;
this.dispatchEvent(new CustomEvent('property-value-change'));
const element = event.target as UmbInputCheckboxListElement;
this.value = element.selection;
this.dispatchEvent(new UmbPropertyValueChangeEvent());
}
render() {
return html`<umb-input-checkbox-list
@change="${this.#onChange}"
.selectedIds="${this.#value}"
.list="${this._list}"></umb-input-checkbox-list>`;
return html`
<umb-input-checkbox-list
.list=${this._list}
.selection=${this.#value}
@change=${this.#onChange}></umb-input-checkbox-list>
`;
}
}

View File

@@ -1,17 +1,14 @@
import type {
UmbCollectionBulkActionPermissions,
UmbCollectionConfiguration,
} from '../../../../core/collection/types.js';
import type { UmbPropertyEditorConfigCollection } from '../../config/index.js';
import { html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UMB_DOCUMENT_COLLECTION_ALIAS } from '@umbraco-cms/backoffice/document';
import { UMB_MEDIA_COLLECTION_ALIAS } from '@umbraco-cms/backoffice/media';
import { UMB_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/property';
import { UMB_WORKSPACE_CONTEXT, UMB_WORKSPACE_COLLECTION_CONTEXT } from '@umbraco-cms/backoffice/workspace';
import type { UmbDocumentWorkspaceContext } from '@umbraco-cms/backoffice/document';
import type { UmbMediaWorkspaceContext } from '@umbraco-cms/backoffice/media';
import { UMB_WORKSPACE_COLLECTION_CONTEXT } from '@umbraco-cms/backoffice/workspace';
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
import type {
UmbCollectionBulkActionPermissions,
UmbCollectionConfiguration,
} from '@umbraco-cms/backoffice/collection';
/**
* @element umb-property-editor-ui-collection-view
@@ -27,7 +24,6 @@ export class UmbPropertyEditorUICollectionViewElement extends UmbLitElement impl
@state()
private _config?: UmbCollectionConfiguration;
@property({ attribute: false })
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
this._config = this.#mapDataTypeConfigToCollectionConfig(config);
}

View File

@@ -1,9 +1,10 @@
import { html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit';
import type { UUIColorSwatchesEvent } from '@umbraco-cms/backoffice/external/uui';
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type { UmbSwatchDetails } from '@umbraco-cms/backoffice/models';
import { UmbPropertyValueChangeEvent } from '@umbraco-cms/backoffice/property-editor';
import type { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor';
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
import type { UmbSwatchDetails } from '@umbraco-cms/backoffice/models';
import type { UUIColorSwatchesEvent } from '@umbraco-cms/backoffice/external/uui';
/**
* @element umb-property-editor-ui-color-picker
@@ -12,8 +13,8 @@ import type { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/
export class UmbPropertyEditorUIColorPickerElement extends UmbLitElement implements UmbPropertyEditorUiElement {
#defaultShowLabels = false;
@property()
value = '';
@property({ type: Object })
value?: UmbSwatchDetails;
@state()
private _showLabels = this.#defaultShowLabels;
@@ -21,23 +22,23 @@ export class UmbPropertyEditorUIColorPickerElement extends UmbLitElement impleme
@state()
private _swatches: UmbSwatchDetails[] = [];
@property({ attribute: false })
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
this._showLabels = config?.getValueByAlias('useLabel') ?? this.#defaultShowLabels;
this._swatches = config?.getValueByAlias('items') ?? [];
}
private _onChange(event: UUIColorSwatchesEvent) {
this.value = event.target.value;
this.dispatchEvent(new CustomEvent('property-value-change'));
const value = event.target.value;
this.value = this._swatches.find((swatch) => swatch.value === value);
this.dispatchEvent(new UmbPropertyValueChangeEvent());
}
render() {
return html`<umb-input-color
@change="${this._onChange}"
.value=${this.value ?? ''}
.swatches="${this._swatches}"
.showLabels="${this._showLabels}"></umb-input-color>`;
?showLabels=${this._showLabels}
.swatches=${this._swatches}
.value=${this.value?.value ?? ''}
@change=${this._onChange}></umb-input-color>`;
}
}

View File

@@ -18,7 +18,6 @@ export class UmbPropertyEditorUIColorSwatchesEditorElement extends UmbLitElement
@state()
private _showLabels = this.#defaultShowLabels;
@property({ attribute: false })
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
this._showLabels = config?.getValueByAlias('useLabel') ?? this.#defaultShowLabels;
}

View File

@@ -26,7 +26,6 @@ export class UmbPropertyEditorUIDatePickerElement extends UmbLitElement implemen
this._valueString = undefined;
}
}
get value() {
return this._valueString;
}
@@ -53,7 +52,6 @@ export class UmbPropertyEditorUIDatePickerElement extends UmbLitElement implemen
private _offsetTime?: boolean;
@property({ attribute: false })
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
if (!config) return;
const oldVal = this._inputType;

View File

@@ -1,56 +1,41 @@
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 { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor';
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
import type { UUISelectEvent } from '@umbraco-cms/backoffice/external/uui';
import type { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
/**
* @element umb-property-editor-ui-dropdown
*/
@customElement('umb-property-editor-ui-dropdown')
export class UmbPropertyEditorUIDropdownElement extends UmbLitElement implements UmbPropertyEditorUiElement {
#value = '';
@property({ type: String })
public get value(): string {
return this.#value;
}
public set value(value: string | undefined) {
this.#value = value?.trim() || '';
}
#selection: Array<string> = [];
@state()
_multiple?: boolean;
@property({ type: Array })
public set value(value: Array<string> | string | undefined) {
this.#selection = Array.isArray(value) ? value : value ? [value] : [];
}
public get value(): Array<string> | undefined {
return this.#selection;
}
@state()
private _list: Array<Option> = [];
@property({ attribute: false })
@state()
private _multiple?: boolean;
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
if (!config) return;
const listData: string[] | undefined = config?.getValueByAlias('items');
this._list = listData?.map((x) => ({ value: x, name: x, selected: this.#selection.includes(x) })) ?? [];
this._multiple = config?.getValueByAlias('multiple');
const listData: Record<number, { value: string; sortOrder: number }> | undefined = config.getValueByAlias('items');
if (!listData) return;
// formatting the items in the dictionary into an array
const sortedItems = [];
const values = Object.values<{ value: string; sortOrder: number }>(listData);
const keys = Object.keys(listData);
for (let i = 0; i < values.length; i++) {
sortedItems.push({ key: keys[i], sortOrder: values[i].sortOrder, value: values[i].value });
}
// ensure the items are sorted by the provided sort order
sortedItems.sort((a, b) => {
return a.sortOrder > b.sortOrder ? 1 : b.sortOrder > a.sortOrder ? -1 : 0;
});
this._list = sortedItems.map((x) => ({ value: x.value, name: x.value, selected: x.value === this.value }));
}
#onChange(event: UUISelectEvent) {
this.value = event.target.value as string;
this.dispatchEvent(new CustomEvent('property-value-change'));
const value = event.target.value as string;
this.value = value ? [value] : [];
this.dispatchEvent(new UmbPropertyValueChangeEvent());
}
render() {

View File

@@ -1,8 +1,9 @@
import { html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit';
import type { UUIColorPickerChangeEvent } from '@umbraco-cms/backoffice/external/uui';
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbPropertyValueChangeEvent } from '@umbraco-cms/backoffice/property-editor';
import type { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor';
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
import type { UUIColorPickerChangeEvent } from '@umbraco-cms/backoffice/external/uui';
/**
* @element umb-property-editor-ui-eye-dropper
@@ -20,25 +21,45 @@ export class UmbPropertyEditorUIEyeDropperElement extends UmbLitElement implemen
@state()
private _swatches: string[] = [];
@property({ attribute: false })
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
if (config) {
this._opacity = config.getValueByAlias('showAlpha') ?? this.#defaultOpacity;
this._swatches = config.getValueByAlias('palette') ?? [];
this._opacity = config?.getValueByAlias('showAlpha') ?? this.#defaultOpacity;
const showPalette = config?.getValueByAlias('showPalette') ?? false;
if (showPalette) {
// TODO: This is a temporary solution until we have a proper way to get the palette from the config. [LK]
this._swatches = [
'#d0021b',
'#f5a623',
'#f8e71c',
'#8b572a',
'#7ed321',
'#417505',
'#bd10e0',
'#9013fe',
'#4a90e2',
'#50e3c2',
'#b8e986',
'#000',
'#444',
'#888',
'#ccc',
'#fff',
];
}
}
private _onChange(event: UUIColorPickerChangeEvent) {
#onChange(event: UUIColorPickerChangeEvent) {
this.value = event.target.value;
this.dispatchEvent(new CustomEvent('property-value-change'));
this.dispatchEvent(new UmbPropertyValueChangeEvent());
}
// TODO: This should use the given value:
render() {
return html`<umb-input-eye-dropper
@change="${this._onChange}"
.opacity=${this._opacity}
.swatches=${this._swatches}
.opacity="${this._opacity}"></umb-input-eye-dropper>`;
.value=${this.value}
@change=${this.#onChange}></umb-input-eye-dropper>`;
}
}

View File

@@ -13,17 +13,16 @@ export class UmbPropertyEditorUIMemberGroupPickerElement extends UmbLitElement i
// private _value: Array<string> = [];
// @property({ type: Array })
// public get value(): Array<string> {
// return this._value;
// }
// public set value(value: Array<string>) {
// this._value = Array.isArray(value) ? value : value ? [value] : [];
// }
// public get value(): Array<string> {
// return this._value;
// }
@property({ type: String })
public value: string = '';
@property({ attribute: false })
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
const validationLimit = config?.find((x) => x.alias === 'validationLimit');
@@ -48,8 +47,8 @@ export class UmbPropertyEditorUIMemberGroupPickerElement extends UmbLitElement i
private _onChange(event: CustomEvent) {
//TODO: This is a hack, something changed so now we need to convert the array to a comma separated string to make it work with the server.
const toCommaSeparatedString = (event.target as UmbInputMemberGroupElement).selectedIds.join(',');
// this.value = (event.target as UmbInputMemberGroupElement).selectedIds;
const toCommaSeparatedString = (event.target as UmbInputMemberGroupElement).selection.join(',');
// this.value = (event.target as UmbInputMemberGroupElement).selection;
this.value = toCommaSeparatedString;
this.dispatchEvent(new CustomEvent('property-value-change'));
}
@@ -58,7 +57,7 @@ export class UmbPropertyEditorUIMemberGroupPickerElement extends UmbLitElement i
return html`
<umb-input-member-group
@change=${this._onChange}
.selectedIds=${this._items}
.selection=${this._items}
.min=${this._limitMin ?? 0}
.max=${this._limitMax ?? Infinity}
>Add</umb-input-member-group

View File

@@ -13,17 +13,16 @@ export class UmbPropertyEditorUIMemberPickerElement extends UmbLitElement implem
// private _value: Array<string> = [];
// @property({ type: Array })
// public get value(): Array<string> {
// return this._value;
// }
// public set value(value: Array<string>) {
// this._value = Array.isArray(value) ? value : value ? [value] : [];
// }
// public get value(): Array<string> {
// return this._value;
// }
@property({ type: String })
public value: string = '';
@property({ attribute: false })
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
const validationLimit = config?.find((x) => x.alias === 'validationLimit');
@@ -48,8 +47,8 @@ export class UmbPropertyEditorUIMemberPickerElement extends UmbLitElement implem
private _onChange(event: CustomEvent) {
//TODO: This is a hack, something changed so now we need to convert the array to a comma separated string to make it work with the server.
const toCommaSeparatedString = (event.target as UmbInputMemberElement).selectedIds.join(',');
// this.value = (event.target as UmbInputMemberElement).selectedIds;
const toCommaSeparatedString = (event.target as UmbInputMemberElement).selection.join(',');
// this.value = (event.target as UmbInputMemberElement).selection;
this.value = toCommaSeparatedString;
this.dispatchEvent(new CustomEvent('property-value-change'));
}
@@ -58,7 +57,7 @@ export class UmbPropertyEditorUIMemberPickerElement extends UmbLitElement implem
return html`
<umb-input-member
@change=${this._onChange}
.selectedIds=${this._items}
.selection=${this._items}
.min=${this._limitMin ?? 0}
.max=${this._limitMax ?? Infinity}
>Add</umb-input-member

View File

@@ -15,7 +15,6 @@ export class UmbPropertyEditorUIMultiUrlPickerElement extends UmbLitElement impl
@property({ type: Array })
value: UmbLinkPickerLink[] = [];
@property({ attribute: false })
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
this._overlaySize = config?.getValueByAlias('overlaySize');
this._hideAnchor = config?.getValueByAlias('hideAnchor');

View File

@@ -14,7 +14,6 @@ export class UmbPropertyEditorUIMultipleTextStringElement extends UmbLitElement
@property({ type: Array })
value?: Array<string>;
@property({ attribute: false })
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
this._limitMin = config?.getValueByAlias('minNumber');
this._limitMax = config?.getValueByAlias('maxNumber');

View File

@@ -13,15 +13,15 @@ import '../../../components/input-number-range/input-number-range.element.js';
@customElement('umb-property-editor-ui-number-range')
export class UmbPropertyEditorUINumberRangeElement extends UmbLitElement implements UmbPropertyEditorUiElement {
@property({ type: Object })
private _value: NumberRangeValueType = { min: undefined, max: undefined };
public get value() {
return this._value;
}
public set value(value: NumberRangeValueType | undefined) {
this._value = value || { min: undefined, max: undefined };
this._minValue = value?.min;
this._maxValue = value?.max;
}
public get value() {
return this._value;
}
private _value: NumberRangeValueType = { min: undefined, max: undefined };
@property({ attribute: false })
public config?: UmbPropertyEditorConfigCollection;

View File

@@ -18,7 +18,6 @@ export class UmbPropertyEditorUINumberElement extends UmbLitElement implements U
@state()
private _step?: number;
@property({ attribute: false })
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
this._min = config?.getValueByAlias('min');
this._max = config?.getValueByAlias('max');

View File

@@ -1,60 +1,39 @@
import type { UmbInputRadioButtonListElement } from '../../../components/input-radio-button-list/input-radio-button-list.element.js';
import '../../../components/input-radio-button-list/input-radio-button-list.element.js';
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 { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor';
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import '../../../components/input-radio-button-list/input-radio-button-list.element.js';
/**
* @element umb-property-editor-ui-radio-button-list
*/
@customElement('umb-property-editor-ui-radio-button-list')
export class UmbPropertyEditorUIRadioButtonListElement extends UmbLitElement implements UmbPropertyEditorUiElement {
#value = '';
@property({ type: String })
public get value(): string {
return this.#value;
}
public set value(value: string | undefined) {
this.#value = value?.trim() || '';
}
@property()
value?: string = '';
@property({ attribute: false })
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
if (!config) return;
const listData: Record<number, { value: string; sortOrder: number }> | undefined = config.getValueByAlias('items');
if (!listData) return;
// formatting the items in the dictionary into an array
const sortedItems = [];
const values = Object.values<{ value: string; sortOrder: number }>(listData);
const keys = Object.keys(listData);
for (let i = 0; i < values.length; i++) {
sortedItems.push({ key: keys[i], sortOrder: values[i].sortOrder, value: values[i].value });
}
// ensure the items are sorted by the provided sort order
sortedItems.sort((a, b) => {
return a.sortOrder > b.sortOrder ? 1 : b.sortOrder > a.sortOrder ? -1 : 0;
});
this._list = sortedItems;
const listData: string[] | undefined = config?.getValueByAlias('items');
this._list = listData?.map((item) => ({ label: item, value: item })) ?? [];
}
@state()
private _list: Array<{ key: string; sortOrder: number; value: string }> = [];
private _list: UmbInputRadioButtonListElement['list'] = [];
#onChange(event: CustomEvent) {
this.value = (event.target as UmbInputRadioButtonListElement).selected;
this.dispatchEvent(new CustomEvent('property-value-change'));
const element = event.target as UmbInputRadioButtonListElement;
this.value = element.value;
this.dispatchEvent(new UmbPropertyValueChangeEvent());
}
render() {
return html`<umb-input-radio-button-list
@change="${this.#onChange}"
.selectedKey="${this.#value}"
.list="${this._list}"></umb-input-radio-button-list>`;
.list=${this._list}
.value=${this.value ?? ''}
@change=${this.#onChange}></umb-input-radio-button-list>`;
}
}

View File

@@ -1,8 +1,9 @@
import type { UmbInputSliderElement } from '../../../components/input-slider/input-slider.element.js';
import { html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit';
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbPropertyValueChangeEvent } from '@umbraco-cms/backoffice/property-editor';
import type { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor';
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
/**
* @element umb-property-editor-ui-slider
@@ -10,12 +11,7 @@ import type { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/
@customElement('umb-property-editor-ui-slider')
export class UmbPropertyEditorUISliderElement extends UmbLitElement implements UmbPropertyEditorUiElement {
@property({ type: Object })
value:
| {
to?: number;
from?: number;
}
| undefined = undefined;
value: { to?: number; from?: number } | undefined = undefined;
@state()
_enableRange?: boolean;
@@ -35,7 +31,6 @@ export class UmbPropertyEditorUISliderElement extends UmbLitElement implements U
@state()
_max?: number;
@property({ attribute: false })
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
this._enableRange = config?.getValueByAlias('enableRange');
this._initVal1 = config?.getValueByAlias('initVal1');
@@ -45,29 +40,26 @@ export class UmbPropertyEditorUISliderElement extends UmbLitElement implements U
this._max = config?.getValueByAlias('maxVal');
}
#getValueObject(val: string) {
if (!val.includes(',')) return { from: parseInt(val), to: parseInt(val) };
const from = val.slice(0, val.indexOf(','));
const to = val.slice(val.indexOf(',') + 1);
return { from: parseInt(from), to: parseInt(to) };
#getValueObject(value: string) {
const [from, to] = value.split(',').map(Number);
return { from, to: to ?? from };
}
private _onChange(event: CustomEvent) {
const eventVal = this.#getValueObject((event.target as UmbInputSliderElement).value as string);
this.value = eventVal;
this.dispatchEvent(new CustomEvent('property-value-change'));
#onChange(event: CustomEvent) {
const element = event.target as UmbInputSliderElement;
this.value = this.#getValueObject(element.value as string);
this.dispatchEvent(new UmbPropertyValueChangeEvent());
}
// TODO: This does not seem to take current value into account?
render() {
return html`<umb-input-slider
.initVal1="${this._initVal1 ?? 0}"
.initVal2="${this._initVal2 ?? 0}"
.step="${this._step ?? 0}"
.min="${this._min ?? 0}"
.max="${this._max ?? 0}"
.valueLow=${this.value?.from ?? this._initVal1 ?? 0}
.valueHigh=${this.value?.to ?? this._initVal2 ?? 0}
.step=${this._step ?? 0}
.min=${this._min ?? 0}
.max=${this._max ?? 0}
?enable-range=${this._enableRange}
@change="${this._onChange}"></umb-input-slider>`;
@change=${this.#onChange}></umb-input-slider>`;
}
}

View File

@@ -32,7 +32,7 @@ export const manifests: Array<ManifestPropertyEditorUi> = [
},
{
type: 'propertyEditorUi',
alias: 'Umb.PropertyEditorUi.Email',
alias: 'Umb.PropertyEditorUi.EmailAddress',
name: 'Email Property Editor UI',
element: () => import('./property-editor-ui-text-box.element.js'),
meta: {

View File

@@ -26,7 +26,6 @@ export class UmbPropertyEditorUITextBoxElement extends UmbLitElement implements
@state()
private _placeholder?: string;
@property({ attribute: false })
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
this._type = config?.getValueByAlias<UuiInputTypeType>('inputType') ?? this.#defaultType;
this._inputMode = config?.getValueByAlias('inputMode');

View File

@@ -15,7 +15,7 @@ export const manifest: ManifestPropertyEditorUi = {
{
alias: 'rows',
label: 'Number of rows',
description: 'If empty the textarea is set to autoheight',
description: 'If empty or zero, the textarea is set to auto-height',
propertyEditorUiAlias: 'Umb.PropertyEditorUi.Number',
},
{

View File

@@ -24,7 +24,6 @@ export class UmbPropertyEditorUITextareaElement extends UmbLitElement implements
@state()
private _css?: any;
@property({ attribute: false })
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
this._maxChars = config?.getValueByAlias('maxChars');
this._rows = config?.getValueByAlias('rows');
@@ -50,7 +49,7 @@ export class UmbPropertyEditorUITextareaElement extends UmbLitElement implements
rows="${ifDefined(this._rows)}"
@input=${this.onInput}
style="${styleMap(this._css)}"
autoheight="${this._rows ? false : true}"></uui-textarea>`;
auto-height=${this._rows ? false : true}></uui-textarea>`;
}
static styles = [

View File

@@ -21,7 +21,6 @@ export class UmbPropertyEditorUIToggleElement extends UmbLitElement implements U
@state()
_showLabels?: boolean;
@property({ attribute: false })
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
this.value ??= config?.getValueByAlias('default') ?? false;
this._labelOff = config?.getValueByAlias('labelOff');

View File

@@ -21,13 +21,13 @@ export class UmbPropertyEditorUITreePickerSourceTypePickerElement
@property()
public set value(value: string) {
if (value) {
this.#selectedIds = value.split(',');
this.#selection = value.split(',');
} else {
this.#selectedIds = [];
this.#selection = [];
}
}
public get value(): string {
return this.#selectedIds.join(',');
return this.#selection.join(',');
}
@state()
@@ -73,20 +73,20 @@ export class UmbPropertyEditorUITreePickerSourceTypePickerElement
#onChange(event: CustomEvent) {
switch (this.sourceType) {
case 'content':
this.#setValue((<UmbInputDocumentTypeElement>event.target).selectedIds);
this.#setValue((<UmbInputDocumentTypeElement>event.target).selection);
break;
case 'media':
this.#setValue((<UmbInputMediaTypeElement>event.target).selectedIds);
this.#setValue((<UmbInputMediaTypeElement>event.target).selection);
break;
case 'member':
this.#setValue((<UmbInputMemberTypeElement>event.target).selectedIds);
this.#setValue((<UmbInputMemberTypeElement>event.target).selection);
break;
default:
break;
}
}
#selectedIds: Array<string> = [];
#selection: Array<string> = [];
#setValue(value: string[]) {
this.value = value.join(',');
@@ -113,19 +113,17 @@ export class UmbPropertyEditorUITreePickerSourceTypePickerElement
#renderTypeContent() {
return html`<umb-input-document-type
@change=${this.#onChange}
.selectedIds=${this.#selectedIds}></umb-input-document-type>`;
.selection=${this.#selection}></umb-input-document-type>`;
}
#renderTypeMedia() {
return html`<umb-input-media-type
@change=${this.#onChange}
.selectedIds=${this.#selectedIds}></umb-input-media-type>`;
return html`<umb-input-media-type @change=${this.#onChange} .selection=${this.#selection}></umb-input-media-type>`;
}
#renderTypeMember() {
return html`<umb-input-member-type
@change=${this.#onChange}
.selectedIds=${this.#selectedIds}></umb-input-member-type>`;
.selection=${this.#selection}></umb-input-member-type>`;
}
}

View File

@@ -41,7 +41,6 @@ export class UmbPropertyEditorUITreePickerElement extends UmbLitElement implemen
#dynamicRootRepository = new UmbDynamicRootRepository(this);
@property({ attribute: false })
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
const startNode: UmbTreePickerSource | undefined = config?.getValueByAlias('startNode');
if (startNode) {

View File

@@ -12,7 +12,6 @@ export class UmbPropertyEditorUIUploadFieldElement extends UmbLitElement impleme
@property()
value = '';
@property({ attribute: false })
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
if (!config) return;

View File

@@ -1,7 +1,9 @@
import { html, customElement, property } from '@umbraco-cms/backoffice/external/lit';
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbPropertyValueChangeEvent } from '@umbraco-cms/backoffice/property-editor';
import type { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor';
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
import type { UmbUserInputElement } from '@umbraco-cms/backoffice/user';
/**
* @element umb-property-editor-ui-user-picker
@@ -9,14 +11,19 @@ import type { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/
@customElement('umb-property-editor-ui-user-picker')
export class UmbPropertyEditorUIUserPickerElement extends UmbLitElement implements UmbPropertyEditorUiElement {
@property()
value = '';
value?: string = '';
@property({ attribute: false })
public config?: UmbPropertyEditorConfigCollection;
// TODO: implement config
#onChange(event: CustomEvent) {
const element = event.target as UmbUserInputElement;
this.value = element.selection.join(',');
this.dispatchEvent(new UmbPropertyValueChangeEvent());
}
render() {
return html` <umb-user-input></umb-user-input>`;
return html`<umb-user-input max="1" .value=${this.value ?? ''} @change=${this.#onChange}></umb-user-input>`;
}
}

View File

@@ -47,15 +47,15 @@ export class UmbPropertyDatasetElement extends UmbLitElement {
* ```
*/
@property({ attribute: false })
public get value(): Array<UmbPropertyValueData> {
return this.context.getValues();
}
public set value(value: Array<UmbPropertyValueData>) {
this.#allowChangeEvent = false;
this.context.setValues(value);
// Above might not trigger a observer callback (if no change), so set the allow change event to true:
this.#allowChangeEvent = true;
}
public get value(): Array<UmbPropertyValueData> {
return this.context.getValues();
}
/**
* The name of the dataset, this name varies depending on the use-case. But this is either
@@ -71,15 +71,15 @@ export class UmbPropertyDatasetElement extends UmbLitElement {
* `
*/
@property({ attribute: false })
public get name(): string | undefined {
return this.context.getName();
}
public set name(value: string | undefined) {
this.#allowChangeEvent = false;
this.context.setName(value);
// Above might not trigger a observer callback (if no change), so set the allow change event to true:
this.#allowChangeEvent = true;
}
public get name(): string | undefined {
return this.context.getName();
}
constructor() {
super();

View File

@@ -3,14 +3,14 @@ import { createRoutePathBuilder } from './generate-route-path-builder.function.j
import type { IRoutingInfo, IRouterSlot } from '@umbraco-cms/backoffice/external/router-slot';
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import { UmbContextBase } from '@umbraco-cms/backoffice/class-api';
import { UMB_MODAL_MANAGER_CONTEXT, type UmbModalRouteRegistration } from '@umbraco-cms/backoffice/modal';
const EmptyDiv = document.createElement('div');
type UmbRoutePlusModalKey = UmbRoute & { __modalKey: string };
export class UmbRouteContext extends UmbControllerBase {
export class UmbRouteContext extends UmbContextBase<UmbRouteContext> {
#mainRouter: IRouterSlot;
#modalRouter: IRouterSlot;
#modalRegistrations: UmbModalRouteRegistration[] = [];
@@ -21,10 +21,9 @@ export class UmbRouteContext extends UmbControllerBase {
#activeModalPath?: string;
constructor(host: UmbControllerHost, mainRouter: IRouterSlot, modalRouter: IRouterSlot) {
super(host);
super(host, UMB_ROUTE_CONTEXT);
this.#mainRouter = mainRouter;
this.#modalRouter = modalRouter;
this.provideContext(UMB_ROUTE_CONTEXT, this);
this.consumeContext(UMB_MODAL_MANAGER_CONTEXT, (context) => {
this.#modalContext = context;
this.#generateModalRoutes();
@@ -35,10 +34,9 @@ export class UmbRouteContext extends UmbControllerBase {
this.#modalRegistrations.push(registration);
this.#createNewUrlBuilder(registration);
this.#generateModalRoutes();
return registration;
}
public unregisterModal(registrationToken: ReturnType<typeof this.registerModal>) {
public unregisterModal(registrationToken: UmbModalRouteRegistration) {
const index = this.#modalRegistrations.indexOf(registrationToken);
if (index === -1) return;
this.#modalRegistrations.splice(index, 1);
@@ -126,7 +124,7 @@ export class UmbRouteContext extends UmbControllerBase {
if (this.#activeModalPath) {
// If if there is a modal using the old path.
const activeModal = this.#modalRegistrations.find((registration) => {
return '/' + registration.generateModalPath() === this.#activeModalPath;
return registration.generateModalPath() === this.#activeModalPath;
});
if (activeModal) {
this.#modalContext?.close(activeModal.key);

View File

@@ -14,12 +14,12 @@ export class UmbInputSectionElement extends FormControlMixin(UmbLitElement) {
* @default 0
*/
@property({ type: Number })
public get min(): number {
return this.#pickerContext.min;
}
public set min(value: number) {
this.#pickerContext.min = value;
}
public get min(): number {
return this.#pickerContext.min;
}
/**
* Min validation message.
@@ -37,12 +37,12 @@ export class UmbInputSectionElement extends FormControlMixin(UmbLitElement) {
* @default Infinity
*/
@property({ type: Number })
public get max(): number {
return this.#pickerContext.max;
}
public set max(value: number) {
this.#pickerContext.max = value;
}
public get max(): number {
return this.#pickerContext.max;
}
/**
* Max validation message.
@@ -53,12 +53,12 @@ export class UmbInputSectionElement extends FormControlMixin(UmbLitElement) {
@property({ type: String, attribute: 'min-message' })
maxMessage = 'This field exceeds the allowed amount of items';
public get selection(): Array<string> {
return this.#pickerContext.getSelection();
}
public set selection(uniques: Array<string>) {
this.#pickerContext.setSelection(uniques);
}
public get selection(): Array<string> {
return this.#pickerContext.getSelection();
}
@property()
public set value(selectionString: string) {
@@ -67,6 +67,9 @@ export class UmbInputSectionElement extends FormControlMixin(UmbLitElement) {
if (selectionString === this.value) return;
this.selection = splitStringToArray(selectionString);
}
public get value(): string {
return this.selection.join(',');
}
@state()
private _items?: Array<UmbSectionItemModel>;

View File

@@ -1,9 +1,9 @@
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
import { UmbContextBase } from '@umbraco-cms/backoffice/class-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbStringState, UmbBooleanState } from '@umbraco-cms/backoffice/observable-api';
export class UmbSectionSidebarContext {
#host: UmbControllerHost;
export class UmbSectionSidebarContext extends UmbContextBase<UmbSectionSidebarContext> {
#contextMenuIsOpen = new UmbBooleanState(false);
contextMenuIsOpen = this.#contextMenuIsOpen.asObservable();
@@ -17,7 +17,7 @@ export class UmbSectionSidebarContext {
headline = this.#headline.asObservable();
constructor(host: UmbControllerHost) {
this.#host = host;
super(host, UMB_SECTION_SIDEBAR_CONTEXT);
}
toggleContextMenu(entityType: string, unique: string | null | undefined, headline: string | undefined) {

View File

@@ -1,4 +1,4 @@
import { UmbSectionSidebarContext, UMB_SECTION_SIDEBAR_CONTEXT } from './section-sidebar.context.js';
import { UmbSectionSidebarContext } from './section-sidebar.context.js';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { css, html, customElement } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
@@ -7,11 +7,6 @@ import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
export class UmbSectionSidebarElement extends UmbLitElement {
#sectionSidebarContext = new UmbSectionSidebarContext(this);
constructor() {
super();
this.provideContext(UMB_SECTION_SIDEBAR_CONTEXT, this.#sectionSidebarContext);
}
render() {
return html`
<umb-section-sidebar-context-menu>

View File

@@ -3,14 +3,14 @@ import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
import type { UmbObserverController } from '@umbraco-cms/backoffice/observable-api';
import { UmbStringState } from '@umbraco-cms/backoffice/observable-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import { UmbContextBase } from '@umbraco-cms/backoffice/class-api';
import type { ManifestTheme } from '@umbraco-cms/backoffice/extension-registry';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
import { loadManifestPlainCss } from '@umbraco-cms/backoffice/extension-api';
const LOCAL_STORAGE_KEY = 'umb-theme-alias';
export class UmbThemeContext extends UmbControllerBase {
export class UmbThemeContext extends UmbContextBase<UmbThemeContext> {
#theme = new UmbStringState('umb-light-theme');
#themeObserver?: UmbObserverController<ManifestTheme[]>;
@@ -19,9 +19,7 @@ export class UmbThemeContext extends UmbControllerBase {
#styleElement: HTMLLinkElement | HTMLStyleElement | null = null;
constructor(host: UmbControllerHost) {
super(host);
this.provideContext(UMB_THEME_CONTEXT, this);
super(host, UMB_THEME_CONTEXT);
const storedTheme = localStorage.getItem(LOCAL_STORAGE_KEY);
if (storedTheme) {

View File

@@ -55,34 +55,34 @@ export class UmbInputTreeElement extends FormControlMixin(UmbLitElement) {
@property({ type: Array })
public set items(items: Array<UmbReferenceByUniqueAndType>) {
this.#selectedIds = items?.map((item) => item.unique) ?? [];
this.#selection = items?.map((item) => item.unique) ?? [];
this.value = items?.map((item) => item.unique).join(',');
}
public get items(): Array<UmbReferenceByUniqueAndType> {
return this.#selectedIds.map((id) => ({ type: this.#entityTypeLookup[this._type], unique: id }));
return this.#selection.map((id) => ({ type: this.#entityTypeLookup[this._type], unique: id }));
}
#selectedIds: Array<string> = [];
#selection: Array<string> = [];
#onChange(event: CustomEvent) {
switch (this._type) {
case 'content':
{
const input = event.target as UmbInputDocumentElement;
this.#selectedIds = input.selectedIds;
this.value = input.selectedIds.join(',');
this.#selection = input.selection;
this.value = input.selection.join(',');
}
break;
case 'media': {
const input = event.target as UmbInputMediaElement;
this.#selectedIds = input.selectedIds;
this.value = input.selectedIds.join(',');
this.#selection = input.selection;
this.value = input.selection.join(',');
break;
}
case 'member': {
const input = event.target as UmbInputMemberElement;
this.#selectedIds = input.selectedIds;
this.value = input.selectedIds.join(',');
this.#selection = input.selection;
this.value = input.selection.join(',');
break;
}
default:
@@ -111,7 +111,7 @@ export class UmbInputTreeElement extends FormControlMixin(UmbLitElement) {
#renderDocumentPicker() {
return html`<umb-input-document
.selectedIds=${this.#selectedIds}
.selection=${this.#selection}
.startNodeId=${this.startNodeId}
.allowedContentTypeIds=${this._allowedContentTypeIds}
.min=${this.min}
@@ -124,7 +124,7 @@ export class UmbInputTreeElement extends FormControlMixin(UmbLitElement) {
#renderMediaPicker() {
// TODO: [LK] Review the data structure of this input editor.
return html`<umb-input-media
.selectedIds=${this.#selectedIds}
.selection=${this.#selection}
.allowedContentTypeIds=${this._allowedContentTypeIds}
.min=${this.min}
.max=${this.max}
@@ -135,7 +135,7 @@ export class UmbInputTreeElement extends FormControlMixin(UmbLitElement) {
#renderMemberPicker() {
return html`<umb-input-member
.selectedIds=${this.#selectedIds}
.selection=${this.#selection}
.allowedContentTypeIds=${this._allowedContentTypeIds}
.min=${this.min}
.max=${this.max}

View File

@@ -21,7 +21,6 @@ export class UmbWorkspaceActionMenuItemElement<
@property({ attribute: false })
public manifest?: ManifestWorkspaceActionMenuItemDefaultKind<MetaType>;
@property({ attribute: false })
public set api(api: ApiType | undefined) {
this.#api = api;

View File

@@ -2,11 +2,11 @@ import { UMB_VARIANT_WORKSPACE_CONTEXT } from '../../workspace-context/index.js'
import { UmbVariantId } from '@umbraco-cms/backoffice/variant';
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import { UmbContextBase } from '@umbraco-cms/backoffice/class-api';
import { UmbNumberState } from '@umbraco-cms/backoffice/observable-api';
import type { UmbPropertyDatasetContext } from '@umbraco-cms/backoffice/property';
export class UmbWorkspaceSplitViewContext extends UmbControllerBase {
export class UmbWorkspaceSplitViewContext extends UmbContextBase<UmbWorkspaceSplitViewContext> {
#workspaceContext?: typeof UMB_VARIANT_WORKSPACE_CONTEXT.TYPE;
public getWorkspaceContext() {
return this.#workspaceContext;
@@ -21,7 +21,7 @@ export class UmbWorkspaceSplitViewContext extends UmbControllerBase {
//variantId = this.#variantId.asObservable();
constructor(host: UmbControllerHost) {
super(host);
super(host, UMB_WORKSPACE_SPLIT_VIEW_CONTEXT);
this.consumeContext(UMB_VARIANT_WORKSPACE_CONTEXT, (context) => {
this.#workspaceContext = context;
@@ -31,8 +31,6 @@ export class UmbWorkspaceSplitViewContext extends UmbControllerBase {
this.observe(this.index, () => {
this._observeVariant();
});
this.provideContext(UMB_WORKSPACE_SPLIT_VIEW_CONTEXT, this);
}
private _observeVariant() {

View File

@@ -1,7 +1,7 @@
import type { UmbPropertyDatasetContext, UmbNameablePropertyDatasetContext } 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 { UmbContextBase } from '@umbraco-cms/backoffice/class-api';
import { UmbVariantId } from '@umbraco-cms/backoffice/variant';
import type { UmbInvariantableWorkspaceContextInterface } from '@umbraco-cms/backoffice/workspace';
@@ -11,7 +11,7 @@ import type { UmbInvariantableWorkspaceContextInterface } from '@umbraco-cms/bac
export class UmbInvariantWorkspacePropertyDatasetContext<
WorkspaceType extends UmbInvariantableWorkspaceContextInterface = UmbInvariantableWorkspaceContextInterface,
>
extends UmbControllerBase
extends UmbContextBase<UmbPropertyDatasetContext>
implements UmbPropertyDatasetContext, UmbNameablePropertyDatasetContext
{
#workspace: WorkspaceType;
@@ -37,13 +37,10 @@ export class UmbInvariantWorkspacePropertyDatasetContext<
}
constructor(host: UmbControllerHost, workspace: WorkspaceType) {
// The controller alias, is a very generic name cause we want only one of these for this controller host.
super(host, 'variantContext');
super(host, UMB_PROPERTY_DATASET_CONTEXT);
this.#workspace = workspace;
this.name = this.#workspace.name;
this.provideContext(UMB_PROPERTY_DATASET_CONTEXT, this);
}
/**

View File

@@ -14,12 +14,12 @@ export class UmbDataTypeInputElement extends FormControlMixin(UmbLitElement) {
* @default 0
*/
@property({ type: Number })
public get min(): number {
return this.#pickerContext.min;
}
public set min(value: number) {
this.#pickerContext.min = value;
}
public get min(): number {
return this.#pickerContext.min;
}
/**
* Min validation message.
@@ -37,12 +37,12 @@ export class UmbDataTypeInputElement extends FormControlMixin(UmbLitElement) {
* @default Infinity
*/
@property({ type: Number })
public get max(): number {
return this.#pickerContext.max;
}
public set max(value: number) {
this.#pickerContext.max = value;
}
public get max(): number {
return this.#pickerContext.max;
}
/**
* Max validation message.
@@ -53,17 +53,20 @@ export class UmbDataTypeInputElement extends FormControlMixin(UmbLitElement) {
@property({ type: String, attribute: 'min-message' })
maxMessage = 'This field exceeds the allowed amount of items';
public get selectedIds(): Array<string> {
public get selection(): Array<string> {
return this.#pickerContext.getSelection();
}
public set selectedIds(ids: Array<string>) {
public set selection(ids: Array<string>) {
this.#pickerContext.setSelection(ids);
}
@property()
public set value(idsString: string) {
// Its with full purpose we don't call super.value, as thats being handled by the observation of the context selection.
this.selectedIds = splitStringToArray(idsString);
this.selection = splitStringToArray(idsString);
}
public get value(): string {
return this.selection.join(',');
}
@state()

View File

@@ -33,12 +33,12 @@ export class UmbInputDocumentTypeElement extends FormControlMixin(UmbLitElement)
* @default 0
*/
@property({ type: Number })
public get min(): number {
return this.#pickerContext.min;
}
public set min(value: number) {
this.#pickerContext.min = value;
}
public get min(): number {
return this.#pickerContext.min;
}
/**
* Min validation message.
@@ -56,12 +56,12 @@ export class UmbInputDocumentTypeElement extends FormControlMixin(UmbLitElement)
* @default Infinity
*/
@property({ type: Number })
public get max(): number {
return this.#pickerContext.max;
}
public set max(value: number) {
this.#pickerContext.max = value;
}
public get max(): number {
return this.#pickerContext.max;
}
/**
* Max validation message.
@@ -73,20 +73,20 @@ export class UmbInputDocumentTypeElement extends FormControlMixin(UmbLitElement)
maxMessage = 'This field exceeds the allowed amount of items';
@property({ type: Array })
public set selectedIds(ids: Array<string> | undefined) {
public set selection(ids: Array<string> | undefined) {
this.#pickerContext.setSelection(ids ?? []);
}
public get selectedIds(): Array<string> {
public get selection(): Array<string> {
return this.#pickerContext.getSelection();
}
@property()
public set value(idsString: string) {
// Its with full purpose we don't call super.value, as thats being handled by the observation of the context selection.
this.selectedIds = splitStringToArray(idsString);
this.selection = splitStringToArray(idsString);
}
public get value(): string {
return this.selectedIds.join(',');
return this.selection.join(',');
}
@state()
@@ -160,7 +160,7 @@ export class UmbInputDocumentTypeElement extends FormControlMixin(UmbLitElement)
}
#renderAddButton() {
if (this.max > 0 && this.selectedIds.length >= this.max) return nothing;
if (this.max > 0 && this.selection.length >= this.max) return nothing;
return html`
<uui-button
id="add-button"

View File

@@ -12,7 +12,6 @@ export class UmbPropertyEditorUIDocumentTypePickerElement extends UmbLitElement
@property()
public value?: string;
@property({ attribute: false })
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
if (config) {
const validationLimit = config.getValueByAlias<any>('validationLimit');
@@ -38,8 +37,8 @@ export class UmbPropertyEditorUIDocumentTypePickerElement extends UmbLitElement
private _onlyElementTypes?: boolean;
private _onChange(event: CustomEvent) {
const selectedIds = (event.target as UmbInputDocumentTypeElement).selectedIds;
this.value = this._multiPicker ? selectedIds.join(',') : selectedIds[0];
const selection = (event.target as UmbInputDocumentTypeElement).selection;
this.value = this._multiPicker ? selection.join(',') : selection[0];
this.dispatchEvent(new UmbPropertyValueChangeEvent());
}

View File

@@ -82,11 +82,11 @@ export class UmbDocumentTypeWorkspaceViewStructureElement extends UmbLitElement
<!-- TODO: maybe we want to somehow display the hierarchy, but not necessary in the same way as old backoffice? -->
<umb-input-document-type
element-types-only
.selectedIds=${this._allowedContentTypeUniques ?? []}
.selection=${this._allowedContentTypeUniques ?? []}
@change="${(e: CustomEvent) => {
const sortedContentTypesList: Array<UmbContentTypeSortModel> = (
e.target as UmbInputDocumentTypeElement
).selectedIds.map((id, index) => ({
).selection.map((id, index) => ({
contentType: { unique: id },
sortOrder: index,
}));

View File

@@ -52,7 +52,7 @@ export class UmbDocumentTypeWorkspaceViewTemplatesElement extends UmbLitElement
// save new allowed ids
const input = e.target as UmbInputTemplateElement;
const idsWithoutRoot =
input.selectedIds
input.selection
?.filter((id) => id !== null)
.map((id) => {
return { id };
@@ -68,7 +68,7 @@ export class UmbDocumentTypeWorkspaceViewTemplatesElement extends UmbLitElement
<div id="templates" slot="editor">
<umb-input-template
.defaultUnique=${this._defaultTemplateId ?? ''}
.selectedIds=${this._allowedTemplateIds}
.selection=${this._allowedTemplateIds}
@change=${this.#templateInputChange}></umb-input-template>
</div>
</umb-property-layout>

View File

@@ -21,7 +21,7 @@ export class UmbInputDocumentElement extends FormControlMixin(UmbLitElement) {
itemSelector: 'uui-ref-node',
containerSelector: 'uui-ref-list',
onChange: ({ model }) => {
this.selectedIds = model;
this.selection = model;
},
});
@@ -32,12 +32,12 @@ export class UmbInputDocumentElement extends FormControlMixin(UmbLitElement) {
* @default 0
*/
@property({ type: Number })
public get min(): number {
return this.#pickerContext.min;
}
public set min(value: number) {
this.#pickerContext.min = value;
}
public get min(): number {
return this.#pickerContext.min;
}
/**
* Min validation message.
@@ -55,12 +55,12 @@ export class UmbInputDocumentElement extends FormControlMixin(UmbLitElement) {
* @default Infinity
*/
@property({ type: Number })
public get max(): number {
return this.#pickerContext.max;
}
public set max(value: number) {
this.#pickerContext.max = value;
}
public get max(): number {
return this.#pickerContext.max;
}
/**
* Max validation message.
@@ -71,10 +71,10 @@ export class UmbInputDocumentElement extends FormControlMixin(UmbLitElement) {
@property({ type: String, attribute: 'min-message' })
maxMessage = 'This field exceeds the allowed amount of items';
public get selectedIds(): Array<string> {
public get selection(): Array<string> {
return this.#pickerContext.getSelection();
}
public set selectedIds(ids: Array<string>) {
public set selection(ids: Array<string>) {
this.#pickerContext.setSelection(ids);
this.#sorter.setModel(ids);
}
@@ -94,10 +94,10 @@ export class UmbInputDocumentElement extends FormControlMixin(UmbLitElement) {
@property()
public set value(idsString: string) {
// Its with full purpose we don't call super.value, as thats being handled by the observation of the context selection.
this.selectedIds = splitStringToArray(idsString);
this.selection = splitStringToArray(idsString);
}
public get value() {
return this.selectedIds.join(',');
return this.selection.join(',');
}
@state()
@@ -177,7 +177,7 @@ export class UmbInputDocumentElement extends FormControlMixin(UmbLitElement) {
}
#renderAddButton() {
if (this.max > 0 && this.selectedIds.length >= this.max) return;
if (this.max === 1 && this.selection.length >= this.max) return;
return html`<uui-button
id="add-button"
look="placeholder"

View File

@@ -32,7 +32,7 @@ export class UmbPublicAccessModalElement extends UmbModalBaseElement<
private _startPage = true;
@state()
private _selectedIds: Array<string> = [];
private _selection: Array<string> = [];
@state()
private _loginPageId?: string;
@@ -76,11 +76,11 @@ export class UmbPublicAccessModalElement extends UmbModalBaseElement<
// Specific or Groups
this._specific = data.members.length > 0 ? true : false;
//SelectedIds
//selection
if (data.members.length > 0) {
this._selectedIds = data.members.map((m: any) => m.id);
this._selection = data.members.map((m: any) => m.id);
} else if (data.groups.length > 0) {
this._selectedIds = data.groups.map((g: any) => g.id);
this._selection = data.groups.map((g: any) => g.id);
}
this._loginPageId = data.loginPageId;
@@ -96,8 +96,8 @@ export class UmbPublicAccessModalElement extends UmbModalBaseElement<
async #handleSave() {
if (!this._loginPageId || !this._errorPageId || !this.#unique) return;
const groups = this._specific ? [] : this._selectedIds;
const members = this._specific ? this._selectedIds : [];
const groups = this._specific ? [] : this._selection;
const members = this._specific ? this._selection : [];
const requestBody: PublicAccessRequestModel = {
memberGroupNames: groups,
@@ -128,19 +128,19 @@ export class UmbPublicAccessModalElement extends UmbModalBaseElement<
// Change Events
#onChangeLoginPage(e: CustomEvent) {
this._loginPageId = (e.target as UmbInputDocumentElement).selectedIds[0];
this._loginPageId = (e.target as UmbInputDocumentElement).selection[0];
}
#onChangeErrorPage(e: CustomEvent) {
this._errorPageId = (e.target as UmbInputDocumentElement).selectedIds[0];
this._errorPageId = (e.target as UmbInputDocumentElement).selection[0];
}
#onChangeGroup(e: CustomEvent) {
this._selectedIds = (e.target as UmbInputMemberTypeElement).selectedIds;
this._selection = (e.target as UmbInputMemberTypeElement).selection;
}
#onChangeMember(e: CustomEvent) {
this._selectedIds = (e.target as UmbInputMemberElement).selectedIds;
this._selection = (e.target as UmbInputMemberElement).selection;
}
// Renders
@@ -204,13 +204,11 @@ export class UmbPublicAccessModalElement extends UmbModalBaseElement<
? html`<umb-localize key="publicAccess_paSelectMembers" .args=${[this._documentName]}>
Select the members who have access to the page <strong>${this._documentName}</strong>
</umb-localize>
<umb-input-member .selectedIds=${this._selectedIds} @change=${this.#onChangeMember}></umb-input-member>`
<umb-input-member .selection=${this._selection} @change=${this.#onChangeMember}></umb-input-member>`
: html`<umb-localize key="publicAccess_paSelectGroups" .args=${[this._documentName]}>
Select the groups who have access to the page <strong>${this._documentName}</strong>
</umb-localize>
<umb-input-member-type
.selectedIds=${this._selectedIds}
@change=${this.#onChangeGroup}></umb-input-member-type>`;
<umb-input-member-type .selection=${this._selection} @change=${this.#onChangeGroup}></umb-input-member-type>`;
}
// Action buttons
@@ -223,7 +221,7 @@ export class UmbPublicAccessModalElement extends UmbModalBaseElement<
look="primary"
color="positive"
label=${this.localize.term('buttons_save')}
?disabled=${!this._loginPageId || !this._errorPageId || this._selectedIds.length === 0}
?disabled=${!this._loginPageId || !this._errorPageId || this._selection.length === 0}
@click="${this.#handleSave}"></uui-button>`
: html`<uui-button
slot="actions"

View File

@@ -8,8 +8,10 @@ import {
} from '@umbraco-cms/backoffice/external/backend-api';
import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
// TODO: Turn this into a Repository with a Store that holds the cache [NL]
/**
* A context for fetching and caching the document configuration.
* @deprecated Do not use this one, it will have ot change in near future.
*/
export class UmbDocumentConfigurationContext extends UmbControllerBase implements UmbApi {
/**
@@ -44,6 +46,9 @@ export class UmbDocumentConfigurationContext extends UmbControllerBase implement
// Export as default to work as a global context:
export default UmbDocumentConfigurationContext;
/**
* @deprecated Do not use this one, it will have ot change in near future.
*/
export const UMB_DOCUMENT_CONFIGURATION_CONTEXT = new UmbContextToken<UmbDocumentConfigurationContext>(
'UmbDocumentConfigurationContext',
);

View File

@@ -3,11 +3,11 @@ import type { UmbDocumentPropertyDataContext } from './document-property-dataset
import type { UmbPropertyDatasetContext } from '@umbraco-cms/backoffice/property';
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
export const IsDocumentVariantContext = (
export const IsDocumentPropertyDatasetContext = (
context: UmbPropertyDatasetContext,
): context is UmbDocumentPropertyDataContext => context.getEntityType() === UMB_DOCUMENT_ENTITY_TYPE;
export const UMB_DOCUMENT_VARIANT_CONTEXT = new UmbContextToken<
export const UMB_DOCUMENT_PROPERTY_DATASET_CONTEXT = new UmbContextToken<
UmbPropertyDatasetContext,
UmbDocumentPropertyDataContext
>('UmbVariantContext', undefined, IsDocumentVariantContext);
>('UmbVariantContext', undefined, IsDocumentPropertyDatasetContext);

View File

@@ -12,7 +12,6 @@ export class UmbPropertyEditorUIDocumentPickerElement extends UmbLitElement impl
@property()
public value?: string;
@property({ attribute: false })
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
const validationLimit = config?.find((x) => x.alias === 'validationLimit');
@@ -29,7 +28,7 @@ export class UmbPropertyEditorUIDocumentPickerElement extends UmbLitElement impl
private _limitMax?: number;
private _onChange(event: CustomEvent) {
this.value = (event.target as UmbInputDocumentElement).selectedIds.join(',');
this.value = (event.target as UmbInputDocumentElement).selection.join(',');
this.dispatchEvent(new UmbPropertyValueChangeEvent());
}

View File

@@ -14,12 +14,12 @@ export class UmbInputLanguageElement extends FormControlMixin(UmbLitElement) {
* @default 0
*/
@property({ type: Number })
public get min(): number {
return this.#pickerContext.min;
}
public set min(value: number) {
this.#pickerContext.min = value;
}
public get min(): number {
return this.#pickerContext.min;
}
/**
* Min validation message.
@@ -37,12 +37,12 @@ export class UmbInputLanguageElement extends FormControlMixin(UmbLitElement) {
* @default Infinity
*/
@property({ type: Number })
public get max(): number {
return this.#pickerContext.max;
}
public set max(value: number) {
this.#pickerContext.max = value;
}
public get max(): number {
return this.#pickerContext.max;
}
/**
* Max validation message.
@@ -56,17 +56,20 @@ export class UmbInputLanguageElement extends FormControlMixin(UmbLitElement) {
@property({ type: Object, attribute: false })
public filter: (language: UmbLanguageItemModel) => boolean = () => true;
public get selectedUniques(): Array<string> {
return this.#pickerContext.getSelection();
}
public set selectedUniques(uniques: Array<string>) {
public set selection(uniques: Array<string>) {
this.#pickerContext.setSelection(uniques);
}
public get selection(): Array<string> {
return this.#pickerContext.getSelection();
}
@property()
public set value(uniques: string) {
// Its with full purpose we don't call super.value, as thats being handled by the observation of the context selection.
this.selectedUniques = splitStringToArray(uniques);
this.selection = splitStringToArray(uniques);
}
public get value(): string {
return this.selection.join(',');
}
@state()

View File

@@ -2,11 +2,13 @@ import { UmbLanguageCollectionRepository } from '../collection/index.js';
import type { UmbLanguageDetailModel } from '../types.js';
import { UmbArrayState, UmbObjectState, createObservablePart } from '@umbraco-cms/backoffice/observable-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import { UmbContextBase } from '@umbraco-cms/backoffice/class-api';
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
import type { UmbApi } from '@umbraco-cms/backoffice/extension-api';
export class UmbAppLanguageContext extends UmbControllerBase implements UmbApi {
// TODO: Make a store for the App Languages.
// TODO: Implement default language end-point, in progress at backend team, so we can avoid getting all languages.
export class UmbAppLanguageContext extends UmbContextBase<UmbAppLanguageContext> implements UmbApi {
#languageCollectionRepository: UmbLanguageCollectionRepository;
#languages = new UmbArrayState<UmbLanguageDetailModel>([], (x) => x.unique);
@@ -24,8 +26,7 @@ export class UmbAppLanguageContext extends UmbControllerBase implements UmbApi {
}
constructor(host: UmbControllerHost) {
super(host);
this.provideContext(UMB_APP_LANGUAGE_CONTEXT, this);
super(host, UMB_APP_LANGUAGE_CONTEXT);
this.#languageCollectionRepository = new UmbLanguageCollectionRepository(this);
this.#observeLanguages();
}

View File

@@ -108,7 +108,7 @@ export class UmbLanguageDetailsWorkspaceViewElement extends UmbLitElement implem
#handleFallbackChange(event: UmbChangeEvent) {
if (event instanceof UmbChangeEvent) {
const target = event.target as UmbInputLanguageElement;
const selectedLanguageUnique = target.selectedUniques?.[0];
const selectedLanguageUnique = target.selection?.[0];
this.#languageWorkspaceContext?.setFallbackCulture(selectedLanguageUnique);
}
}
@@ -149,7 +149,7 @@ export class UmbLanguageDetailsWorkspaceViewElement extends UmbLitElement implem
${this._language?.isDefault && this._language?.isDefault !== this._isDefaultLanguage
? html`<div id="default-language-warning">
Switching default language may result in default content missing.
</div>`
</div>`
: nothing}
<hr />

View File

@@ -20,7 +20,6 @@ export class UmbPropertyEditorUIMarkdownEditorElement extends UmbLitElement impl
@state()
private _overlaySize?: UUIModalSidebarSize;
@property({ attribute: false })
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
this._preview = config?.getValueByAlias('preview');
this._overlaySize = config?.getValueByAlias('overlaySize') ?? undefined;

View File

@@ -14,12 +14,12 @@ export class UmbInputMediaTypeElement extends FormControlMixin(UmbLitElement) {
* @default 0
*/
@property({ type: Number })
public get min(): number {
return this.#pickerContext.min;
}
public set min(value: number) {
this.#pickerContext.min = value;
}
public get min(): number {
return this.#pickerContext.min;
}
/**
* Min validation message.
@@ -37,12 +37,12 @@ export class UmbInputMediaTypeElement extends FormControlMixin(UmbLitElement) {
* @default Infinity
*/
@property({ type: Number })
public get max(): number {
return this.#pickerContext.max;
}
public set max(value: number) {
this.#pickerContext.max = value;
}
public get max(): number {
return this.#pickerContext.max;
}
/**
* Max validation message.
@@ -53,21 +53,20 @@ export class UmbInputMediaTypeElement extends FormControlMixin(UmbLitElement) {
@property({ type: String, attribute: 'min-message' })
maxMessage = 'This field exceeds the allowed amount of items';
@property({ type: Array })
public set selectedIds(ids: Array<string>) {
public set selection(ids: Array<string>) {
this.#pickerContext.setSelection(ids);
}
public get selectedIds(): Array<string> {
public get selection(): Array<string> {
return this.#pickerContext.getSelection();
}
@property()
public set value(idsString: string) {
// Its with full purpose we don't call super.value, as thats being handled by the observation of the context selection.
this.selectedIds = splitStringToArray(idsString);
this.selection = splitStringToArray(idsString);
}
public get value() {
return this.selectedIds.join(',');
return this.selection.join(',');
}
@state()
@@ -122,7 +121,7 @@ export class UmbInputMediaTypeElement extends FormControlMixin(UmbLitElement) {
}
#renderAddButton() {
if (this.max > 0 && this.selectedIds.length >= this.max) return;
if (this.max === 1 && this.selection.length >= this.max) return;
return html`
<uui-button
id="add-button"

View File

@@ -12,7 +12,6 @@ export class UmbPropertyEditorUIMediaTypePickerElement extends UmbLitElement imp
@property()
public value?: string;
@property({ attribute: false })
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
if (config) {
const validationLimit = config.getValueByAlias<any>('validationLimit');
@@ -30,7 +29,7 @@ export class UmbPropertyEditorUIMediaTypePickerElement extends UmbLitElement imp
private _limitMax?: number;
private _onChange(event: CustomEvent) {
this.value = (event.target as UmbInputMediaTypeElement).selectedIds.join(',');
this.value = (event.target as UmbInputMediaTypeElement).selection.join(',');
this.dispatchEvent(new UmbPropertyValueChangeEvent());
}

View File

@@ -81,11 +81,11 @@ export class UmbMediaTypeWorkspaceViewStructureElement extends UmbLitElement imp
<div slot="editor">
<!-- TODO: maybe we want to somehow display the hierarchy, but not necessary in the same way as old backoffice? -->
<umb-input-media-type
.selectedIds=${this._allowedContentTypeIDs ?? []}
.selection=${this._allowedContentTypeIDs ?? []}
@change="${(e: CustomEvent) => {
const sortedContentTypesList: Array<UmbContentTypeSortModel> = (
e.target as UmbInputMediaTypeElement
).selectedIds.map((id, index) => ({
).selection.map((id, index) => ({
contentType: { unique: id },
sortOrder: index,
}));

View File

@@ -24,7 +24,7 @@ export class UmbInputMediaElement extends FormControlMixin(UmbLitElement) {
#sorter = new UmbSorterController(this, {
...SORTER_CONFIG,
onChange: ({ model }) => {
this.selectedIds = model;
this.selection = model;
},
});
@@ -35,12 +35,12 @@ export class UmbInputMediaElement extends FormControlMixin(UmbLitElement) {
* @default 0
*/
@property({ type: Number })
public get min(): number {
return this.#pickerContext.min;
}
public set min(value: number) {
this.#pickerContext.min = value;
}
public get min(): number {
return this.#pickerContext.min;
}
/**
* Min validation message.
@@ -58,12 +58,12 @@ export class UmbInputMediaElement extends FormControlMixin(UmbLitElement) {
* @default Infinity
*/
@property({ type: Number })
public get max(): number {
return this.#pickerContext.max;
}
public set max(value: number) {
this.#pickerContext.max = value;
}
public get max(): number {
return this.#pickerContext.max;
}
/**
* Max validation message.
@@ -74,13 +74,13 @@ export class UmbInputMediaElement extends FormControlMixin(UmbLitElement) {
@property({ type: String, attribute: 'min-message' })
maxMessage = 'This field exceeds the allowed amount of items';
public get selectedIds(): Array<string> {
return this.#pickerContext.getSelection();
}
public set selectedIds(ids: Array<string>) {
public set selection(ids: Array<string>) {
this.#pickerContext.setSelection(ids);
this.#sorter.setModel(ids);
}
public get selection(): Array<string> {
return this.#pickerContext.getSelection();
}
@property({ type: Array })
allowedContentTypeIds?: string[] | undefined;
@@ -94,10 +94,10 @@ export class UmbInputMediaElement extends FormControlMixin(UmbLitElement) {
@property()
public set value(idsString: string) {
// Its with full purpose we don't call super.value, as thats being handled by the observation of the context selection.
this.selectedIds = splitStringToArray(idsString);
this.selection = splitStringToArray(idsString);
}
public get value() {
return this.selectedIds.join(',');
return this.selection.join(',');
}
@state()

View File

@@ -36,7 +36,6 @@ export class UmbPropertyEditorUIImageCropperElement extends UmbLitElement implem
}
}
@property({ attribute: false })
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
this.crops = config?.getValueByAlias<UmbImageCropperPropertyEditorValue['crops']>('crops') ?? [];
}

View File

@@ -26,7 +26,6 @@ export class UmbPropertyEditorUIMediaPickerElement extends UmbLitElement impleme
return this.#value;
}
@property({ attribute: false })
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
const validationLimit = config?.getByAlias('validationLimit');
if (!validationLimit) return;
@@ -51,9 +50,9 @@ export class UmbPropertyEditorUIMediaPickerElement extends UmbLitElement impleme
#value: Array<UmbMediaPickerPropertyValue> = [];
#onChange(event: CustomEvent) {
const selectedIds = (event.target as UmbInputMediaElement).selectedIds;
const selection = (event.target as UmbInputMediaElement).selection;
const result = selectedIds.map((mediaKey) => {
const result = selection.map((mediaKey) => {
return {
key: UmbId.new(),
mediaKey,
@@ -72,7 +71,7 @@ export class UmbPropertyEditorUIMediaPickerElement extends UmbLitElement impleme
return html`
<umb-input-media
@change=${this.#onChange}
.selectedIds=${this._items}
.selection=${this._items}
.min=${this._limitMin}
.max=${this._limitMax}>
<umb-localize key="general_add">Add</umb-localize>

View File

@@ -25,7 +25,7 @@ export class UmbInputMemberGroupElement extends FormControlMixin(UmbLitElement)
#sorter = new UmbSorterController(this, {
...SORTER_CONFIG,
onChange: ({ model }) => {
this.selectedIds = model;
this.selection = model;
},
});
@@ -36,12 +36,12 @@ export class UmbInputMemberGroupElement extends FormControlMixin(UmbLitElement)
* @default 0
*/
@property({ type: Number })
public get min(): number {
return this.#pickerContext.min;
}
public set min(value: number) {
this.#pickerContext.min = value;
}
public get min(): number {
return this.#pickerContext.min;
}
/**
* Min validation message.
@@ -59,12 +59,12 @@ export class UmbInputMemberGroupElement extends FormControlMixin(UmbLitElement)
* @default Infinity
*/
@property({ type: Number })
public get max(): number {
return this.#pickerContext.max;
}
public set max(value: number) {
this.#pickerContext.max = value;
}
public get max(): number {
return this.#pickerContext.max;
}
/**
* Max validation message.
@@ -75,13 +75,13 @@ export class UmbInputMemberGroupElement extends FormControlMixin(UmbLitElement)
@property({ type: String, attribute: 'min-message' })
maxMessage = 'This field exceeds the allowed amount of items';
public get selectedIds(): Array<string> {
return this.#pickerContext.getSelection();
}
public set selectedIds(ids: Array<string>) {
public set selection(ids: Array<string>) {
this.#pickerContext.setSelection(ids);
this.#sorter.setModel(ids);
}
public get selection(): Array<string> {
return this.#pickerContext.getSelection();
}
@property({ type: Boolean })
showOpenButton?: boolean;
@@ -92,7 +92,10 @@ export class UmbInputMemberGroupElement extends FormControlMixin(UmbLitElement)
@property()
public set value(idsString: string) {
// Its with full purpose we don't call super.value, as thats being handled by the observation of the context selection.
this.selectedIds = splitStringToArray(idsString);
this.selection = splitStringToArray(idsString);
}
public get value(): string {
return this.selection.join(',');
}
@property({ type: Object, attribute: false })
@@ -109,6 +112,7 @@ export class UmbInputMemberGroupElement extends FormControlMixin(UmbLitElement)
constructor() {
super();
// TODO: This would have to be more specific if used in a property editor context... [NL]
new UmbModalRouteRegistrationController(this, UMB_WORKSPACE_MODAL)
.addAdditionalPath('member-group')
.onSetup(() => {
@@ -180,7 +184,7 @@ export class UmbInputMemberGroupElement extends FormControlMixin(UmbLitElement)
}
#renderAddButton() {
if (this.max > 0 && this.selectedIds.length >= this.max) return;
if (this.max === 1 && this.selection.length >= this.max) return;
return html`<uui-button
id="add-button"
look="placeholder"

View File

@@ -53,17 +53,20 @@ export class UmbInputMemberTypeElement extends FormControlMixin(UmbLitElement) {
@property({ type: String, attribute: 'min-message' })
maxMessage = 'This field exceeds the allowed amount of items';
public set selectedIds(ids: Array<string>) {
public set selection(ids: Array<string>) {
this.#pickerContext.setSelection(ids);
}
public get selectedIds(): Array<string> {
public get selection(): Array<string> {
return this.#pickerContext.getSelection();
}
@property()
public set value(idsString: string) {
// Its with full purpose we don't call super.value, as thats being handled by the observation of the context selection.
this.selectedIds = splitStringToArray(idsString);
// 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);
}
public get value(): string {
return this.selection.join(',');
}
@state()
@@ -118,7 +121,7 @@ export class UmbInputMemberTypeElement extends FormControlMixin(UmbLitElement) {
}
#renderAddButton() {
if (this.max > 0 && this.selectedIds.length >= this.max) return;
if (this.max === 1 && this.selection.length >= this.max) return;
return html`
<uui-button
id="add-button"

View File

@@ -25,7 +25,7 @@ export class UmbInputMemberElement extends FormControlMixin(UmbLitElement) {
#sorter = new UmbSorterController(this, {
...SORTER_CONFIG,
onChange: ({ model }) => {
this.selectedIds = model;
this.selection = model;
},
});
@@ -36,12 +36,12 @@ export class UmbInputMemberElement extends FormControlMixin(UmbLitElement) {
* @default 0
*/
@property({ type: Number })
public get min(): number {
return this.#pickerContext.min;
}
public set min(value: number) {
this.#pickerContext.min = value;
}
public get min(): number {
return this.#pickerContext.min;
}
/**
* Min validation message.
@@ -59,12 +59,12 @@ export class UmbInputMemberElement extends FormControlMixin(UmbLitElement) {
* @default Infinity
*/
@property({ type: Number })
public get max(): number {
return this.#pickerContext.max;
}
public set max(value: number) {
this.#pickerContext.max = value;
}
public get max(): number {
return this.#pickerContext.max;
}
/**
* Max validation message.
@@ -75,13 +75,13 @@ export class UmbInputMemberElement extends FormControlMixin(UmbLitElement) {
@property({ type: String, attribute: 'min-message' })
maxMessage = 'This field exceeds the allowed amount of items';
public get selectedIds(): Array<string> {
return this.#pickerContext.getSelection();
}
public set selectedIds(ids: Array<string>) {
public set selection(ids: Array<string>) {
this.#pickerContext.setSelection(ids);
this.#sorter.setModel(ids);
}
public get selection(): Array<string> {
return this.#pickerContext.getSelection();
}
@property({ type: Boolean })
showOpenButton?: boolean;
@@ -92,7 +92,10 @@ export class UmbInputMemberElement extends FormControlMixin(UmbLitElement) {
@property()
public set value(idsString: string) {
// Its with full purpose we don't call super.value, as thats being handled by the observation of the context selection.
this.selectedIds = splitStringToArray(idsString);
this.selection = splitStringToArray(idsString);
}
public get value(): string {
return this.selection.join(',');
}
@property({ type: Object, attribute: false })
@@ -180,7 +183,7 @@ export class UmbInputMemberElement extends FormControlMixin(UmbLitElement) {
}
#renderAddButton() {
if (this.max > 0 && this.selectedIds.length >= this.max) return;
if (this.max === 1 && this.selection.length >= this.max) return;
return html`<uui-button
id="add-button"
look="placeholder"

View File

@@ -42,15 +42,16 @@ export class UmbMemberWorkspaceViewMemberElement extends UmbLitElement implement
}
#onGroupsUpdated(event: CustomEvent) {
const uniques = (event.target as UmbInputMemberGroupElement).selectedIds;
const uniques = (event.target as UmbInputMemberGroupElement).selection;
this._workspaceContext?.set('groups', uniques);
}
#onPasswordUpdate = () => {
const newPassword = this.shadowRoot?.querySelector<HTMLInputElement>('uui-input[name="newPassword"]')?.value;
const confirmPassword = this.shadowRoot?.querySelector<HTMLInputElement>('uui-input[name="confirmPassword"]')
?.value;
const confirmPassword = this.shadowRoot?.querySelector<HTMLInputElement>(
'uui-input[name="confirmPassword"]',
)?.value;
if (newPassword !== confirmPassword) {
this._newPasswordError = 'Passwords do not match';
@@ -157,7 +158,7 @@ export class UmbMemberWorkspaceViewMemberElement extends UmbLitElement implement
<umb-input-member-group
slot="editor"
@change=${this.#onGroupsUpdated}
.selectedIds=${this._workspaceContext.memberGroups}></umb-input-member-group>
.selection=${this._workspaceContext.memberGroups}></umb-input-member-group>
</umb-property-layout>
<umb-property-layout label="Approved">

View File

@@ -125,7 +125,7 @@ export class UmbWorkspacePackageBuilderElement extends UmbLitElement {
${this._package?.id
? html`<uui-button @click="${this.#download}" color="" look="secondary" label="Download package">
Download
</uui-button>`
</uui-button>`
: nothing}
<uui-button
@click="${this._package.id ? this.#update : this.#save}"
@@ -176,7 +176,7 @@ export class UmbWorkspacePackageBuilderElement extends UmbLitElement {
.value=${this._package.contentNodeId ?? ''}
max="1"
@change="${(e: CustomEvent) =>
(this._package.contentNodeId = (e.target as UmbInputDocumentElement).selectedIds[0])}">
(this._package.contentNodeId = (e.target as UmbInputDocumentElement).selection[0])}">
</umb-input-document>
<uui-checkbox
label="Include child nodes"
@@ -192,9 +192,9 @@ export class UmbWorkspacePackageBuilderElement extends UmbLitElement {
return html`
<div slot="editor">
<umb-input-media
.selectedIds=${this._package.mediaIds ?? []}
.selection=${this._package.mediaIds ?? []}
@change="${(e: CustomEvent) =>
(this._package.mediaIds = (e.target as UmbInputMediaElement).selectedIds)}"></umb-input-media>
(this._package.mediaIds = (e.target as UmbInputMediaElement).selection)}"></umb-input-media>
<uui-checkbox
label="Include child nodes"
.checked="${this._package.mediaLoadChildNodes ?? false}"
@@ -222,7 +222,7 @@ export class UmbWorkspacePackageBuilderElement extends UmbLitElement {
<umb-input-language
.value="${this._package.languages?.join(',') ?? ''}"
@change="${(e: CustomEvent) => {
this._package.languages = (e.target as UmbInputLanguageElement).selectedUniques;
this._package.languages = (e.target as UmbInputLanguageElement).selection;
}}"></umb-input-language>
</div>`;
}

View File

@@ -14,12 +14,12 @@ export class UmbInputStaticFileElement extends FormControlMixin(UmbLitElement) {
* @default 0
*/
@property({ type: Number })
public get min(): number {
return this.#pickerContext.min;
}
public set min(value: number) {
this.#pickerContext.min = value;
}
public get min(): number {
return this.#pickerContext.min;
}
/**
* Min validation message.
@@ -37,12 +37,12 @@ export class UmbInputStaticFileElement extends FormControlMixin(UmbLitElement) {
* @default Infinity
*/
@property({ type: Number })
public get max(): number {
return this.#pickerContext.max;
}
public set max(value: number) {
this.#pickerContext.max = value;
}
public get max(): number {
return this.#pickerContext.max;
}
/**
* Max validation message.
@@ -53,18 +53,21 @@ export class UmbInputStaticFileElement extends FormControlMixin(UmbLitElement) {
@property({ type: String, attribute: 'min-message' })
maxMessage = 'This field exceeds the allowed amount of files';
public get selectedPaths(): Array<string> {
return this.#pickerContext.getSelection();
}
public set selectedPaths(paths: Array<string>) {
public set selection(paths: Array<string>) {
this.#pickerContext.setSelection(paths);
}
public get selection(): Array<string> {
return this.#pickerContext.getSelection();
}
@property()
// get value is handled by super class.
public 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.selectedPaths = splitStringToArray(pathsString);
this.selection = splitStringToArray(pathsString);
}
public get value(): string {
return this.selection.join(',');
}
@state()
@@ -104,14 +107,14 @@ export class UmbInputStaticFileElement extends FormControlMixin(UmbLitElement) {
(item) => item.unique,
(item) => this._renderItem(item),
)}
</uui-ref-list>`
</uui-ref-list>`
: ''}
${this.#renderAddButton()}
`;
}
#renderAddButton() {
if (this.max > 0 && this.selectedPaths.length >= this.max) return;
if (this.max === 1 && this.selection.length >= this.max) return;
return html`<uui-button
id="add-button"
look="placeholder"

View File

@@ -20,8 +20,8 @@ describe('UmbInputStaticFileElement', () => {
describe('Public API', () => {
describe('properties', () => {
it('has a selectedPaths property', () => {
expect(element).to.have.property('selectedPaths').to.be.an.instanceOf(Array);
it('has a selection property', () => {
expect(element).to.have.property('selection').to.be.an.instanceOf(Array);
});
it('has a value property', () => {

View File

@@ -10,14 +10,13 @@ export class UmbPropertyEditorUIStaticFilePickerElement extends UmbLitElement im
private _value: Array<string> = [];
@property({ type: Array })
public get value(): Array<string> {
return this._value;
}
public set value(value: Array<string>) {
this._value = value || [];
}
public get value(): Array<string> {
return this._value;
}
@property({ attribute: false })
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
const validationLimit = config?.find((x) => x.alias === 'validationLimit');
@@ -31,7 +30,7 @@ export class UmbPropertyEditorUIStaticFilePickerElement extends UmbLitElement im
private _limitMax?: number;
private _onChange(event: CustomEvent) {
this.value = (event.target as UmbInputStaticFileElement).selectedPaths;
this.value = (event.target as UmbInputStaticFileElement).selection;
this.dispatchEvent(new CustomEvent('property-value-change'));
}
@@ -40,7 +39,7 @@ export class UmbPropertyEditorUIStaticFilePickerElement extends UmbLitElement im
return html`
<umb-input-static-file
@change=${this._onChange}
.selectedIds=${this._value}
.selection=${this._value}
.min=${this._limitMin ?? 0}
.max=${this._limitMax ?? Infinity}></umb-input-static-file>
`;

View File

@@ -185,22 +185,22 @@ export class UmbTagsInputElement extends FormControlMixin(UmbLitElement) {
<div id="wrapper">
${this.#enteredTags()}
<span id="main-tag-wrapper">
<uui-tag id="input-width-tracker" aria-hidden="true" style="visibility:hidden;opacity:0;position:absolute;">
${this._currentInput}
</uui-tag>
<uui-tag look="outline" id="main-tag" @click="${this.focus}" slot="trigger">
<input
id="tag-input"
aria-label="tag input"
placeholder="Enter tag"
.value="${this._currentInput ?? undefined}"
@keydown="${this.#onKeydown}"
@input="${this.#onInput}"
@blur="${this.#onBlur}" />
<uui-icon id="icon-add" name="icon-add"></uui-icon>
${this.#renderTagOptions()}
</uui-tag>
<span>
<uui-tag id="input-width-tracker" aria-hidden="true" style="visibility:hidden;opacity:0;position:absolute;">
${this._currentInput}
</uui-tag>
<uui-tag look="outline" id="main-tag" @click="${this.focus}" slot="trigger">
<input
id="tag-input"
aria-label="tag input"
placeholder="Enter tag"
.value="${this._currentInput ?? undefined}"
@keydown="${this.#onKeydown}"
@input="${this.#onInput}"
@blur="${this.#onBlur}" />
<uui-icon id="icon-add" name="icon-add"></uui-icon>
${this.#renderTagOptions()}
</uui-tag>
</span>
</div>
`;
}
@@ -230,10 +230,10 @@ export class UmbTagsInputElement extends FormControlMixin(UmbLitElement) {
class="options"
id="tag-${tag.id}"
type="radio"
name="${tag.group}"
name="${tag.group ?? ''}"
@click="${() => this.#optionClick(index)}"
@keydown="${(e: KeyboardEvent) => this.#optionKeydown(e, index)}"
value="${tag.text}" />
value="${tag.text ?? ''}" />
<label for="tag-${tag.id}"> ${tag.text} </label>`;
},
)}

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