From 0475fba86815876dc7c6f980c35cdb448e4565b0 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Thu, 27 Mar 2025 10:40:38 +0100 Subject: [PATCH 01/13] docs: changes code samples to use UmbChangeEvent and adds `{% code %}` tags --- .../composition/property-editor-ui.md | 84 ++++++++++++------- 1 file changed, 52 insertions(+), 32 deletions(-) diff --git a/15/umbraco-cms/customizing/property-editors/composition/property-editor-ui.md b/15/umbraco-cms/customizing/property-editors/composition/property-editor-ui.md index 8d669948fe2..0f79bb681b0 100644 --- a/15/umbraco-cms/customizing/property-editors/composition/property-editor-ui.md +++ b/15/umbraco-cms/customizing/property-editors/composition/property-editor-ui.md @@ -14,6 +14,7 @@ The Property Editor UI is a pure front-end extension. This determines how the da ### Property Editor UI +{% code title="umbraco-package.json" %} ```json { "type": "propertyEditorUi", @@ -29,6 +30,7 @@ The Property Editor UI is a pure front-end extension. This determines how the da } } ``` +{% endcode %} The Property Editor UI cannot be used for Content Types if no Property Editor Schema is specified in the manifest. However, it can still be utilized to manipulate JSON. A case of that could be a Settings property for another Property Editor UI or Schema. @@ -42,6 +44,7 @@ The Property Editor UI inherits the Settings of its Property Editor Schema. **Manifest** +{% code title="umbraco-package.json" %} ```json { "type": "propertyEditorUi", @@ -68,47 +71,64 @@ The Property Editor UI inherits the Settings of its Property Editor Schema. }, }; ``` +{% endcode %} ## The Property Editor UI Element -Inherit the interface, to secure your Element live up to the requirements of this. +Implement the `UmbPropertyEditorUiElement` interface, to secure your Element live up to the requirements of this. ```typescript -// TODO: get interface -interface UmbPropertyEditorUIElement {} +interface UmbPropertyEditorUiElement extends HTMLElement { + name?: string; + value?: unknown; + config?: UmbPropertyEditorConfigCollection; + mandatory?: boolean; + mandatoryMessage?: string; + destroy?: () => void; +} ``` +{% hint style="info" %} +The `UmbPropertyEditorUiElement` interface is a TypeScript interface that ensures that your Element has the necessary properties and methods to be used as a Property Editor UI Element. See the [UI API Docs](https://apidocs.umbraco.com/v15/ui-api/interfaces/packages_core_property-editor.UmbPropertyEditorUiElement.html) for more information. +{% endhint %} + **Example with LitElement** +{% code title="my-text-box.ts" lineNumbers="true" %} ```typescript -import { LitElement, html, css, customElement, property } from '@umbraco-cms/backoffice/external/lit'; -import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api'; -import { UmbPropertyValueChangeEvent } from '@umbraco-cms/backoffice/property-editor'; - -@customElement('my-text-box') -export default class UmbPropertyEditorUITextBoxElement extends UmbElementMixin(LitElement) { - - @property() - value: string | undefined; - - @property({ attribute: false }) - public config: UmbPropertyEditorConfigCollection | undefined; - - private onInput(e: InputEvent) { - this.value = (e.target as HTMLInputElement).value; - this.dispatchEvent(new UmbPropertyValueChangeEvent()); - } - - render() { - return html``; - } - - static styles = [ - css` - uui-input { - width: 100%; - } - `, - ]; +import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; +import { css, html, property } from '@umbraco-cms/backoffice/external/lit'; +import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; +import type { + UmbPropertyEditorConfigCollection, + UmbPropertyEditorUiElement, +} from '@umbraco-cms/backoffice/property-editor'; +import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; + +export default class UmbPropertyEditorUITextBoxElement extends UmbLitElement implements UmbPropertyEditorUiElement { + @property() + value?: string; + + @property({ attribute: false }) + config?: UmbPropertyEditorConfigCollection; + + #onInput(e: InputEvent) { + this.value = (e.target as HTMLInputElement).value; + this.dispatchEvent(new UmbChangeEvent()); + } + + override render() { + return html``; + } + + static override readonly styles = [ + UmbTextStyles, + css` + uui-input { + width: 100%; + } + `, + ]; } ``` +{% endcode %} From 923802840cf1c82b884cba8762bd764db019e90e Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Thu, 27 Mar 2025 10:42:11 +0100 Subject: [PATCH 02/13] fix: registers element as custom element --- .../property-editors/composition/property-editor-ui.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/15/umbraco-cms/customizing/property-editors/composition/property-editor-ui.md b/15/umbraco-cms/customizing/property-editors/composition/property-editor-ui.md index 0f79bb681b0..5822c1ab107 100644 --- a/15/umbraco-cms/customizing/property-editors/composition/property-editor-ui.md +++ b/15/umbraco-cms/customizing/property-editors/composition/property-editor-ui.md @@ -97,7 +97,7 @@ The `UmbPropertyEditorUiElement` interface is a TypeScript interface that ensure {% code title="my-text-box.ts" lineNumbers="true" %} ```typescript import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; -import { css, html, property } from '@umbraco-cms/backoffice/external/lit'; +import { css, customElement, html, property } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import type { UmbPropertyEditorConfigCollection, @@ -105,6 +105,7 @@ import type { } from '@umbraco-cms/backoffice/property-editor'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; +@customElement('umb-property-editor-ui-text-box') export default class UmbPropertyEditorUITextBoxElement extends UmbLitElement implements UmbPropertyEditorUiElement { @property() value?: string; @@ -130,5 +131,11 @@ export default class UmbPropertyEditorUITextBoxElement extends UmbLitElement imp `, ]; } + +declare global { + interface HTMLElementTagNameMap { + 'umb-property-editor-ui-text-box': UmbPropertyEditorUITextBoxElement; + } +} ``` {% endcode %} From 0e9d9bccafc549002aeb0cea147b2de2042a10c4 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Thu, 27 Mar 2025 10:59:52 +0100 Subject: [PATCH 03/13] docs: corrects usages of TypeScript --- .../tutorials/creating-a-property-editor/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/15/umbraco-cms/tutorials/creating-a-property-editor/README.md b/15/umbraco-cms/tutorials/creating-a-property-editor/README.md index 7b1acf66445..76f0cad31c7 100644 --- a/15/umbraco-cms/tutorials/creating-a-property-editor/README.md +++ b/15/umbraco-cms/tutorials/creating-a-property-editor/README.md @@ -16,16 +16,16 @@ The steps we will go through in part one are: * [Adding styling and setting up events in Web Components](./#adding-styling-and-setting-up-events-in-the-web-components) * [Setup Event Logic](./#setup-event-logic) -This tutorial uses Typescript and Lit with Umbraco, It is expected that your package is already [set up to use Typescript and Lit](../../customizing/development-flow/vite-package-setup.md). +This tutorial uses TypeScript and Lit with Umbraco, It is expected that your package is already [set up to use TypeScript and Lit](../../customizing/development-flow/vite-package-setup.md). -To see how to set up an extension in Umbraco using Typescript and Lit, read the article [Creating your first extension](../creating-your-first-extension.md). +To see how to set up an extension in Umbraco using TypeScript and Lit, read the article [Creating your first extension](../creating-your-first-extension.md). ### **Resources** -This tutorial will not go in-depth on how Typescript and Lit work. To learn about Typescript and Lit, you can find their documentation below: +This tutorial will not go in-depth on how TypeScript and Lit work. To learn about TypeScript and Lit, you can find their documentation below: -* [Typescript Docs](https://www.typescriptlang.org/docs/) -* [Lit Docs](https://lit.dev/docs/) +* [TypeScript documentation](https://www.typescriptlang.org/docs/) +* [Lit documentation](https://lit.dev/docs/) ### The End Result From 6899aece7795d55260ade3513632369ddc4ba6ed Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Thu, 27 Mar 2025 11:04:22 +0100 Subject: [PATCH 04/13] docs: adapts code examples to latest best practice including changing `UmbPropertyValueChangeEvent` to `UmbChangeEvent` --- .../creating-a-property-editor/README.md | 214 ++++++----- ...ding-configuration-to-a-property-editor.md | 189 +++++----- ...egrating-context-with-a-property-editor.md | 350 +++++++++--------- 3 files changed, 370 insertions(+), 383 deletions(-) diff --git a/15/umbraco-cms/tutorials/creating-a-property-editor/README.md b/15/umbraco-cms/tutorials/creating-a-property-editor/README.md index 76f0cad31c7..f3c400b44fe 100644 --- a/15/umbraco-cms/tutorials/creating-a-property-editor/README.md +++ b/15/umbraco-cms/tutorials/creating-a-property-editor/README.md @@ -83,17 +83,17 @@ Now let's create the web component we need for our property editor. 1. Create a file in the `src` folder with the name `suggestions-property-editor-ui.element.ts` 2. In this new file, add the following code: -{% code title="suggestions-property-editor-ui.element.ts" %} +{% code title="suggestions-property-editor-ui.element.ts" lineNumbers="true" %} ```typescript -import { LitElement, html, customElement, property } from "@umbraco-cms/backoffice/external/lit"; -import { UmbPropertyEditorUiElement } from "@umbraco-cms/backoffice/property-editor"; +import { LitElement, html, customElement, property } from '@umbraco-cms/backoffice/external/lit'; +import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/property-editor'; @customElement('my-suggestions-property-editor-ui') export default class MySuggestionsPropertyEditorUIElement extends LitElement implements UmbPropertyEditorUiElement { @property({ type: String }) public value = ""; - render() { + override render() { return html`I'm a property editor!`; } } @@ -139,7 +139,7 @@ Let's start by creating an input field and some buttons that we can style and ho {% code title="suggestions-property-editor-ui.element.ts" %} ```typescript -render() { +override render() { return html` + id="suggestion-button" + class="element" + look="primary" + label="give me suggestions" + @click=${this.#onSuggestion} + > Give me suggestions! - + ... - `; - } + `; +} ``` {% endcode %} @@ -396,88 +401,81 @@ import { LitElement, html, css, customElement, property, state } from "@umbraco- {% code title="suggestions-property-editor-ui.element.ts" lineNumbers="true" %} ```typescript -import { LitElement, css, html, customElement, property, state } from "@umbraco-cms/backoffice/external/lit"; -import { UmbPropertyEditorUiElement } from "@umbraco-cms/backoffice/extension-registry"; -import { UmbPropertyValueChangeEvent } from '@umbraco-cms/backoffice/property-editor'; +import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; +import { css, customElement, html, LitElement, property, state } from '@umbraco-cms/backoffice/external/lit'; +import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/property-editor'; +import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; @customElement('my-suggestions-property-editor-ui') export default class MySuggestionsPropertyEditorUIElement extends LitElement implements UmbPropertyEditorUiElement { - @property({ type: String }) - public value = ""; - - @state() - private _suggestions = [ - "You should take a break", - "I suggest that you visit the Eiffel Tower", - "How about starting a book club today or this week?", - "Are you hungry?", - ]; - - #onInput(e: InputEvent) { - this.value = (e.target as HTMLInputElement).value; - this.#dispatchChangeEvent(); - } - - #onSuggestion() { - const randomIndex = (this._suggestions.length * Math.random()) | 0; - this.value = this._suggestions[randomIndex]; - this.#dispatchChangeEvent(); - } - - #dispatchChangeEvent() { - this.dispatchEvent(new UmbPropertyValueChangeEvent()); - } - - render() { - return html` - - -
- - Give me suggestions! - - - Trim text - -
- `; - } - - static styles = [ - css` - #wrapper { - margin-top: 10px; - display: flex; - gap: 10px; - } - .element { - width: 100%; - } - `, - ]; + @property({ type: String }) + public value = ''; + + @state() + private _suggestions = [ + 'You should take a break', + 'I suggest that you visit the Eiffel Tower', + 'How about starting a book club today or this week?', + 'Are you hungry?', + ]; + + #onInput(e: InputEvent) { + this.value = (e.target as HTMLInputElement).value; + this.#dispatchChangeEvent(); + } + + #onSuggestion() { + const randomIndex = (this._suggestions.length * Math.random()) | 0; + this.value = this._suggestions[randomIndex]; + this.#dispatchChangeEvent(); + } + + #dispatchChangeEvent() { + this.dispatchEvent(new UmbChangeEvent()); + } + + override render() { + return html` + + +
+ + Give me suggestions! + + Trim text +
+ `; + } + + static override readonly styles = [ + UmbTextStyles, + css` + #wrapper { + margin-top: 10px; + display: flex; + gap: 10px; + } + .element { + width: 100%; + } + `, + ]; } declare global { - interface HTMLElementTagNameMap { - 'my-suggestions-property-editor-ui': MySuggestionsPropertyEditorUIElement; - } + interface HTMLElementTagNameMap { + 'my-suggestions-property-editor-ui': MySuggestionsPropertyEditorUIElement; + } } ``` {% endcode %} @@ -494,6 +492,6 @@ Learn more about extending this service by visiting the [Property Editors](../.. ## Going further -With all the steps completed, we have created a Suggestion data type running in our property editor. +With all the steps completed, we have created a Suggestion Data Type running in our property editor. In the next part, we will look at adding configurations to our property editor. diff --git a/15/umbraco-cms/tutorials/creating-a-property-editor/adding-configuration-to-a-property-editor.md b/15/umbraco-cms/tutorials/creating-a-property-editor/adding-configuration-to-a-property-editor.md index 694880f834a..4b733818e44 100644 --- a/15/umbraco-cms/tutorials/creating-a-property-editor/adding-configuration-to-a-property-editor.md +++ b/15/umbraco-cms/tutorials/creating-a-property-editor/adding-configuration-to-a-property-editor.md @@ -264,110 +264,105 @@ import { ifDefined } from "@umbraco-cms/backoffice/external/lit"; See the entire file: suggestions-property-editor-ui.element.ts -{% code title="suggestions-property-editor-ui.element.ts" %} +{% code title="suggestions-property-editor-ui.element.ts" lineNumbers="true" %} ```typescript -import { LitElement, css, html, customElement, property, state, ifDefined } from "@umbraco-cms/backoffice/external/lit"; -import { type UmbPropertyEditorUiElement } from "@umbraco-cms/backoffice/extension-registry"; -import { type UmbPropertyEditorConfigCollection } from "@umbraco-cms/backoffice/property-editor"; -import { UmbPropertyValueChangeEvent } from '@umbraco-cms/backoffice/property-editor'; +import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; +import { css, customElement, html, ifDefined, LitElement, property, state } from '@umbraco-cms/backoffice/external/lit'; +import type { + UmbPropertyEditorConfigCollection, + UmbPropertyEditorUiElement, +} from '@umbraco-cms/backoffice/property-editor'; +import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; @customElement('my-suggestions-property-editor-ui') export default class MySuggestionsPropertyEditorUIElement extends LitElement implements UmbPropertyEditorUiElement { - @property({ type: String }) - public value = ""; - - @state() - private _disabled?: boolean; - - @state() - private _placeholder?: string; - - @state() - private _maxChars?: number; - - @state() - private _suggestions = [ - "You should take a break", - "I suggest that you visit the Eiffel Tower", - "How about starting a book club today or this week?", - "Are you hungry?", - ]; - - @property({ attribute: false }) - public set config(config: UmbPropertyEditorConfigCollection) { - this._disabled = config.getValueByAlias("disabled"); - this._placeholder = config.getValueByAlias("placeholder"); - this._maxChars = config.getValueByAlias("maxChars"); - } - - #onInput(e: InputEvent) { - this.value = (e.target as HTMLInputElement).value; - this.#dispatchChangeEvent(); - } - - #onSuggestion() { - const randomIndex = (this._suggestions.length * Math.random()) | 0; - this.value = this._suggestions[randomIndex]; - this.#dispatchChangeEvent(); - } - - #dispatchChangeEvent() { - this.dispatchEvent(new UmbPropertyValueChangeEvent()); - } - - render() { - return html` - - -
- - Give me suggestions! - - - Trim text - -
- `; - } - - static styles = [ - css` - #wrapper { - margin-top: 10px; - display: flex; - gap: 10px; - } - .element { - width: 100%; - } - `, - ]; + @property({ type: String }) + public value = ''; + + @state() + private _disabled?: boolean; + + @state() + private _placeholder?: string; + + @state() + private _maxChars?: number; + + @state() + private _suggestions = [ + 'You should take a break', + 'I suggest that you visit the Eiffel Tower', + 'How about starting a book club today or this week?', + 'Are you hungry?', + ]; + + @property({ attribute: false }) + public set config(config: UmbPropertyEditorConfigCollection) { + this._disabled = config.getValueByAlias('disabled'); + this._placeholder = config.getValueByAlias('placeholder'); + this._maxChars = config.getValueByAlias('maxChars'); + } + + #onInput(e: InputEvent) { + this.value = (e.target as HTMLInputElement).value; + this.#dispatchChangeEvent(); + } + + #onSuggestion() { + const randomIndex = (this._suggestions.length * Math.random()) | 0; + this.value = this._suggestions[randomIndex]; + this.#dispatchChangeEvent(); + } + + #dispatchChangeEvent() { + this.dispatchEvent(new UmbChangeEvent()); + } + + override render() { + return html` + + +
+ + Give me suggestions! + + Trim text +
+ `; + } + + static override readonly styles = [ + UmbTextStyles, + css` + #wrapper { + margin-top: 10px; + display: flex; + gap: 10px; + } + .element { + width: 100%; + } + `, + ]; } declare global { - interface HTMLElementTagNameMap { - 'my-suggestions-property-editor-ui': MySuggestionsPropertyEditorUIElement; - } + interface HTMLElementTagNameMap { + 'my-suggestions-property-editor-ui': MySuggestionsPropertyEditorUIElement; + } } ``` {% endcode %} diff --git a/15/umbraco-cms/tutorials/creating-a-property-editor/integrating-context-with-a-property-editor.md b/15/umbraco-cms/tutorials/creating-a-property-editor/integrating-context-with-a-property-editor.md index 47bcca55db6..b3cafebc503 100644 --- a/15/umbraco-cms/tutorials/creating-a-property-editor/integrating-context-with-a-property-editor.md +++ b/15/umbraco-cms/tutorials/creating-a-property-editor/integrating-context-with-a-property-editor.md @@ -20,8 +20,8 @@ The steps we will go through in this part are: {% code title="suggestions-property-editor-ui.element.ts" %} ```typescript -import { UMB_NOTIFICATION_CONTEXT, UmbNotificationContext, UmbNotificationDefaultData} from "@umbraco-cms/backoffice/notification"; -import { UmbElementMixin } from "@umbraco-cms/backoffice/element-api"; +import { UMB_NOTIFICATION_CONTEXT, UmbNotificationContext, UmbNotificationDefaultData} from '@umbraco-cms/backoffice/notification'; +import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api'; ``` {% endcode %} @@ -38,13 +38,13 @@ export default class MySuggestionsPropertyEditorUIElement extends UmbElementMixi {% code title="suggestions-property-editor-ui.element.ts" %} ```typescript - _notificationContext?: UmbNotificationContext; +#notificationContext?: UmbNotificationContext; constructor() { super(); this.consumeContext(UMB_NOTIFICATION_CONTEXT, (instance) => { - this._notificationContext = instance; + this.#notificationContext = instance; }); } ``` @@ -56,21 +56,21 @@ Now we can use the notification context, let's change our `#onTrimText` method. First, check if the length of our input is smaller or equal to our maxLength configuration. If it is, we have nothing to trim and will send a notification saying there is nothing to trim. -Here we can use the NotificationContext's peek method. It has two parameters `UmbNotificationColor` and an`UmbNotificationDefaultData` object. +Here we can use the NotificationContext's peek method. It has two parameters `UmbNotificationColor` and an `UmbNotificationDefaultData` object. 1. Add the `#onTextTrim()`method above the `render()` method: {% code title="suggestions-property-editor-ui.element.ts" %} ```typescript #onTextTrim() { - if (!this._maxChars) return; - if (!this.value || (this.value as string).length <= this._maxChars) { - const data: UmbNotificationDefaultData = { - message: `Nothing to trim!`, - }; - this._notificationContext?.peek("danger", { data }); - return; - } + if (!this._maxChars) return; + if (!this.value || (this.value as string).length <= this._maxChars) { + const data: UmbNotificationDefaultData = { + message: `Nothing to trim!`, + }; + this.#notificationContext?.peek("danger", { data }); + return; + } } ``` {% endcode %} @@ -79,15 +79,12 @@ Here we can use the NotificationContext's peek method. It has two parameters `Um {% code title="suggestions-property-editor-ui.element.ts" %} ```typescript - - Trim text - + ``` {% endcode %} @@ -107,11 +104,11 @@ Like the notification context, we need to import it and consume it in the constr {% code title="suggestions-property-editor-ui.element.ts" %} ```typescript -import { UMB_MODAL_MANAGER_CONTEXT, UMB_CONFIRM_MODAL,} from "@umbraco-cms/backoffice/modal"; +import { UMB_MODAL_MANAGER_CONTEXT, UMB_CONFIRM_MODAL,} from '@umbraco-cms/backoffice/modal'; ``` {% endcode %} -2. Remove the `UmbNotificationContext` from the `"@umbraco-cms/backoffice/notification"` import: +2. Remove the `UmbNotificationContext` from the `'@umbraco-cms/backoffice/notification'` import: ```typescript import { UMB_NOTIFICATION_CONTEXT, UmbNotificationDefaultData } from "@umbraco-cms/backoffice/notification"; @@ -121,17 +118,17 @@ import { UMB_NOTIFICATION_CONTEXT, UmbNotificationDefaultData } from "@umbraco-c {% code title="suggestions-property-editor-ui.element.ts" %} ```typescript -_modalManagerContext?: typeof UMB_MODAL_MANAGER_CONTEXT.TYPE; -_notificationContext?: typeof UMB_NOTIFICATION_CONTEXT.TYPE; +#modalManagerContext?: typeof UMB_MODAL_MANAGER_CONTEXT.TYPE; +#notificationContext?: typeof UMB_NOTIFICATION_CONTEXT.TYPE; constructor() { super(); this.consumeContext(UMB_MODAL_MANAGER_CONTEXT, (instance) => { - this._modalManagerContext = instance; + this.#modalManagerContext = instance; }); this.consumeContext(UMB_NOTIFICATION_CONTEXT, (instance) => { - this._notificationContext = instance; + this.#notificationContext = instance; }); } ``` @@ -145,7 +142,7 @@ constructor() { ... const trimmed = (this.value as string).substring(0, this._maxChars); - const modalHandler = this._modalManagerContext?.open(this, UMB_CONFIRM_MODAL, + const modalHandler = this.#modalManagerContext?.open(this, UMB_CONFIRM_MODAL, { data: { headline: `Trim text`, @@ -162,7 +159,7 @@ constructor() { headline: `Text trimmed`, message: `You trimmed the text!`, }; - this._notificationContext?.peek("positive", { data }); + this.#notificationContext?.peek("positive", { data }); }, null); } ``` @@ -179,159 +176,156 @@ constructor() { See the entire file: suggestions-property-editor-ui.element.ts -{% code title="suggestions-property-editor-ui.element.ts" %} +{% code title="suggestions-property-editor-ui.element.ts" lineNumbers="true" %} ```typescript -import { LitElement, css, html, customElement, property, state, ifDefined } from "@umbraco-cms/backoffice/external/lit"; -import { type UmbPropertyEditorUiElement } from "@umbraco-cms/backoffice/extension-registry"; -import { type UmbPropertyEditorConfigCollection } from "@umbraco-cms/backoffice/property-editor"; -import { UmbPropertyValueChangeEvent } from '@umbraco-cms/backoffice/property-editor'; -import { UMB_NOTIFICATION_CONTEXT, UmbNotificationDefaultData } from "@umbraco-cms/backoffice/notification"; -import { UmbElementMixin } from "@umbraco-cms/backoffice/element-api"; -import { UMB_MODAL_MANAGER_CONTEXT, UMB_CONFIRM_MODAL, } from "@umbraco-cms/backoffice/modal"; -@customElement('my-suggestions-property-editor-ui') -export default class MySuggestionsPropertyEditorUIElement extends UmbElementMixin((LitElement)) implements UmbPropertyEditorUiElement { - @property({ type: String }) - public value = ""; - - @state() - private _disabled?: boolean; - - @state() - private _placeholder?: string; - - @state() - private _maxChars?: number; - - @state() - private _suggestions = [ - "You should take a break", - "I suggest that you visit the Eiffel Tower", - "How about starting a book club today or this week?", - "Are you hungry?", - ]; - - @property({ attribute: false }) - public set config(config: UmbPropertyEditorConfigCollection) { - this._disabled = config.getValueByAlias("disabled"); - this._placeholder = config.getValueByAlias("placeholder"); - this._maxChars = config.getValueByAlias("maxChars"); - } - - #onInput(e: InputEvent) { - this.value = (e.target as HTMLInputElement).value; - this.#dispatchChangeEvent(); - } - - #onSuggestion() { - const randomIndex = (this._suggestions.length * Math.random()) | 0; - this.value = this._suggestions[randomIndex]; - this.#dispatchChangeEvent(); - } - - #dispatchChangeEvent() { - this.dispatchEvent(new UmbPropertyValueChangeEvent()); - } - - _modalManagerContext?: typeof UMB_MODAL_MANAGER_CONTEXT.TYPE; - _notificationContext?: typeof UMB_NOTIFICATION_CONTEXT.TYPE; - - constructor() { - super(); - this.consumeContext(UMB_MODAL_MANAGER_CONTEXT, (instance) => { - this._modalManagerContext = instance; - }); - - this.consumeContext(UMB_NOTIFICATION_CONTEXT, (instance) => { - this._notificationContext = instance; - }); - } - - #onTextTrim() { - if (!this._maxChars) return; - if (!this.value || (this.value as string).length <= this._maxChars) { - const data: UmbNotificationDefaultData = { - message: `Nothing to trim!`, - }; - this._notificationContext?.peek("danger", { data }); - return; - } - const trimmed = (this.value as string).substring(0, this._maxChars); - const modalHandler = this._modalManagerContext?.open(this, UMB_CONFIRM_MODAL, - { - data: { - headline: `Trim text`, - content: `Do you want to trim the text to "${trimmed}"?`, - color: "danger", - confirmLabel: "Trim", - } - } - ); - modalHandler?.onSubmit().then(() => { - this.value = trimmed; - this.#dispatchChangeEvent(); - const data: UmbNotificationDefaultData = { - headline: `Text trimmed`, - message: `You trimmed the text!`, - }; - this._notificationContext?.peek("positive", { data }); - }, null); - } - +import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api'; +import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; +import { css, customElement, html, ifDefined, LitElement, property, state } from '@umbraco-cms/backoffice/external/lit'; +import { UMB_CONFIRM_MODAL, UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; +import { UMB_NOTIFICATION_CONTEXT, type UmbNotificationDefaultData } from '@umbraco-cms/backoffice/notification'; +import type { + UmbPropertyEditorConfigCollection, + UmbPropertyEditorUiElement, +} from '@umbraco-cms/backoffice/property-editor'; +import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; -render() { - return html` - - -
- - Give me suggestions! - - - Trim text - -
- `; -} - - static styles = [ - css` - #wrapper { - margin-top: 10px; - display: flex; - gap: 10px; - } - .element { - width: 100%; - } - `, -]; +@customElement('my-suggestions-property-editor-ui') +export default class MySuggestionsPropertyEditorUIElement + extends UmbElementMixin(LitElement) + implements UmbPropertyEditorUiElement +{ + @property({ type: String }) + public value = ''; + + @state() + private _disabled?: boolean; + + @state() + private _placeholder?: string; + + @state() + private _maxChars?: number; + + @state() + private _suggestions = [ + 'You should take a break', + 'I suggest that you visit the Eiffel Tower', + 'How about starting a book club today or this week?', + 'Are you hungry?', + ]; + + @property({ attribute: false }) + public set config(config: UmbPropertyEditorConfigCollection) { + this._disabled = config.getValueByAlias('disabled'); + this._placeholder = config.getValueByAlias('placeholder'); + this._maxChars = config.getValueByAlias('maxChars'); + } + + #onInput(e: InputEvent) { + this.value = (e.target as HTMLInputElement).value; + this.#dispatchChangeEvent(); + } + + #onSuggestion() { + const randomIndex = (this._suggestions.length * Math.random()) | 0; + this.value = this._suggestions[randomIndex]; + this.#dispatchChangeEvent(); + } + + #dispatchChangeEvent() { + this.dispatchEvent(new UmbChangeEvent()); + } + + #modalManagerContext?: typeof UMB_MODAL_MANAGER_CONTEXT.TYPE; + #notificationContext?: typeof UMB_NOTIFICATION_CONTEXT.TYPE; + + constructor() { + super(); + this.consumeContext(UMB_MODAL_MANAGER_CONTEXT, (instance) => { + this.#modalManagerContext = instance; + }); + + this.consumeContext(UMB_NOTIFICATION_CONTEXT, (instance) => { + this.#notificationContext = instance; + }); + } + + #onTextTrim() { + if (!this._maxChars) return; + if (!this.value || (this.value as string).length <= this._maxChars) { + const data: UmbNotificationDefaultData = { + message: `Nothing to trim!`, + }; + this.#notificationContext?.peek('danger', { data }); + return; + } + const trimmed = (this.value as string).substring(0, this._maxChars); + const modalHandler = this.#modalManagerContext?.open(this, UMB_CONFIRM_MODAL, { + data: { + headline: `Trim text`, + content: `Do you want to trim the text to "${trimmed}"?`, + color: 'danger', + confirmLabel: 'Trim', + }, + }); + modalHandler?.onSubmit().then(() => { + this.value = trimmed; + this.#dispatchChangeEvent(); + const data: UmbNotificationDefaultData = { + headline: `Text trimmed`, + message: `You trimmed the text!`, + }; + this.#notificationContext?.peek('positive', { data }); + }, null); + } + + override render() { + return html` + + +
+ + Give me suggestions! + + + Trim text + +
+ `; + } + + static override readonly styles = [ + UmbTextStyles, + css` + #wrapper { + margin-top: 10px; + display: flex; + gap: 10px; + } + .element { + width: 100%; + } + `, + ]; } declare global { - interface HTMLElementTagNameMap { - 'my-suggestions-property-editor-ui': MySuggestionsPropertyEditorUIElement; - } + interface HTMLElementTagNameMap { + 'my-suggestions-property-editor-ui': MySuggestionsPropertyEditorUIElement; + } } ``` {% endcode %} From 0da34e212078a290f6a5add7aeffd79eb70ad679 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Thu, 27 Mar 2025 11:06:07 +0100 Subject: [PATCH 05/13] docs: adapt to `UmbChangeEvent` --- .../developer/extending/adding-a-fieldtype.md | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/15/umbraco-forms/developer/extending/adding-a-fieldtype.md b/15/umbraco-forms/developer/extending/adding-a-fieldtype.md index c1b0289ea57..8ab71b312c6 100644 --- a/15/umbraco-forms/developer/extending/adding-a-fieldtype.md +++ b/15/umbraco-forms/developer/extending/adding-a-fieldtype.md @@ -261,11 +261,11 @@ import { html, customElement, } from "@umbraco-cms/backoffice/external/lit"; -import type { UmbPropertyEditorUiElement } from "@umbraco-cms/backoffice/extension-registry"; +import type { UmbPropertyEditorUiElement } from "@umbraco-cms/backoffice/property-editor"; import { UmbLitElement } from "@umbraco-cms/backoffice/lit-element"; import { - UmbPropertyValueChangeEvent, -} from "@umbraco-cms/backoffice/property-editor"; + UmbChangeEvent, +} from "@umbraco-cms/backoffice/event"; import { UmbFormControlMixin } from "@umbraco-cms/backoffice/validation"; const elementName = "my-property-editor-ui-number"; @@ -279,10 +279,10 @@ export class MyPropertyEditorUINumberElement const newValue = (e.target as HTMLInputElement).value; if (newValue === this.value) return; this.value = newValue; - this.dispatchEvent(new UmbPropertyValueChangeEvent()); + this.dispatchEvent(new UmbChangeEvent()); } - render() { + override render() { return html` Date: Thu, 27 Mar 2025 11:17:48 +0100 Subject: [PATCH 06/13] docs: uses correct import paths --- .../extension-types/menu.md | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/15/umbraco-cms/customizing/extending-overview/extension-types/menu.md b/15/umbraco-cms/customizing/extending-overview/extension-types/menu.md index d61f8f00cd4..2209b21685e 100644 --- a/15/umbraco-cms/customizing/extending-overview/extension-types/menu.md +++ b/15/umbraco-cms/customizing/extending-overview/extension-types/menu.md @@ -36,7 +36,7 @@ The manifest can also be written in TypeScript. For this TypeScript example we used a [Backoffice Entry Point](../../extending-overview/extension-types/backoffice-entry-point.md) extension to register the manifests. ```typescript -import { ManifestMenu } from "@umbraco-cms/backoffice/extension-registry"; +import type { ManifestMenu } from "@umbraco-cms/backoffice/menu"; const menuManifest: Array = [ { @@ -55,7 +55,7 @@ const menuManifest: Array = [

Menu Item

-Menu items are the items that appear in the menu. +Menu items are the items that appear in the menu. ## Creating a custom menu items @@ -139,10 +139,9 @@ You can fetch the data and render the menu items using the Lit element above. By {% code title="menu-items.ts" overflow="wrap" lineNumbers="true" %} ```typescript -import { UmbMenuItemElement } from '@umbraco-cms/backoffice/extension-registry'; +import type { UmbMenuItemElement } from '@umbraco-cms/backoffice/menu'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; -import { html, TemplateResult } from 'lit'; -import { customElement, state } from 'lit/decorators.js'; +import { html, TemplateResult, customElement, state } from '@umbraco-cms/backoffice/external/lit'; import { MyMenuItemResponseModel, MyMenuResource } from '../../../api'; const elementName = 'my-menu-item'; @@ -151,13 +150,14 @@ const elementName = 'my-menu-item'; class MyMenuItems extends UmbLitElement implements UmbMenuItemElement { @state() private _items: MyMenuItemResponseModel[] = []; // Store fetched items + @state() private _loading: boolean = true; // Track loading state + @state() private _error: string | null = null; // Track any errors - constructor() { - super(); + override firstUpdated() { this.fetchInitialItems(); // Start fetching on component load } @@ -178,8 +178,8 @@ class MyMenuItems extends UmbLitElement implements UmbMenuItemElement { return html` ${items.map(element => html` - ${element.type === 1 - ? html`` + ${element.type === 1 + ? html`` : html``} ${element.hasChildren ? this.renderItems(element.children) : ''} @@ -189,7 +189,7 @@ class MyMenuItems extends UmbLitElement implements UmbMenuItemElement { } // Main render function - render() { + override render() { if (this._loading) { return html``; } @@ -200,7 +200,7 @@ class MyMenuItems extends UmbLitElement implements UmbMenuItemElement { } // Render items if loading is done and no error occurred - return html`${this.renderItems(this._items)}`; + return this.renderItems(this._items); } } @@ -212,7 +212,7 @@ declare global { } } -``` +``` {% endcode %} @@ -220,7 +220,7 @@ declare global { ### Manifest -```typescript +```json // it will be something like this { "type": "menuItem", @@ -236,9 +236,10 @@ declare global { #### Default Element +The default element supports rendering a subtree of menu items. + ```typescript -// get interface -interface UmbTreeMenuItemElement {} +class UmbMenuItemTreeDefaultElement {} ``` ### Adding menu items to an existing menu From 738ae64d8f8ab9b9cbb610a344b729d5253830c1 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Thu, 27 Mar 2025 11:18:04 +0100 Subject: [PATCH 07/13] docs: uses correct import paths --- .../extension-types/modals/custom-modals.md | 14 +++++++++----- .../extension-types/sections/section-view.md | 6 +++--- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/15/umbraco-cms/customizing/extending-overview/extension-types/modals/custom-modals.md b/15/umbraco-cms/customizing/extending-overview/extension-types/modals/custom-modals.md index 068f284d98b..4698f64ed0a 100644 --- a/15/umbraco-cms/customizing/extending-overview/extension-types/modals/custom-modals.md +++ b/15/umbraco-cms/customizing/extending-overview/extension-types/modals/custom-modals.md @@ -50,9 +50,8 @@ Additionally, the modal element can see its data parameters through the `modalCo ```ts import { html, LitElement, property, customElement } from "@umbraco-cms/backoffice/external/lit"; import { UmbElementMixin } from "@umbraco-cms/backoffice/element-api"; -import type { UmbModalContext } from "@umbraco-cms/backoffice/modal"; +import { type UmbModalContext, UmbModalExtensionElement } from "@umbraco-cms/backoffice/modal"; import type { MyModalData, MyModalValue } from "./my-modal.token.ts"; -import { UmbModalExtensionElement } from "@umbraco-cms/backoffice/extension-registry"; @customElement('my-dialog') export default class MyDialogElement @@ -109,8 +108,7 @@ To open the modal, you need to consume the `UmbModalManagerContext` and then use import { MY_MODAL_TOKEN } from './my-modal.token'; import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api'; -import { LitElement, html } from 'lit'; -import { customElement } from 'lit/decorators.js'; +import { LitElement, html, customElement } from '@umbraco-cms/backoffice/external/lit'; @customElement('my-element') class MyElement extends UmbElementMixin(LitElement) { @@ -124,7 +122,7 @@ class MyElement extends UmbElementMixin(LitElement) { }); } - render() { + override render() { return html` `; @@ -138,5 +136,11 @@ class MyElement extends UmbElementMixin(LitElement) { }); } } + +declare global { + interface HTMLElementTagNameMap { + 'my-element': MyElement; + } +} ``` {% endcode %} diff --git a/15/umbraco-cms/customizing/extending-overview/extension-types/sections/section-view.md b/15/umbraco-cms/customizing/extending-overview/extension-types/sections/section-view.md index 0e83e85a43a..6ee280adb83 100644 --- a/15/umbraco-cms/customizing/extending-overview/extension-types/sections/section-view.md +++ b/15/umbraco-cms/customizing/extending-overview/extension-types/sections/section-view.md @@ -51,7 +51,7 @@ The manifest can also be written in TypeScript. For this TypeScript example we used a [Backoffice Entry Point](../backoffice-entry-point.md) extension to register the manifests. ```typescript -import { ManifestSectionView } from "@umbraco-cms/backoffice/extension-registry"; +import { ManifestSectionView } from "@umbraco-cms/backoffice/section"; const sectionViews: Array = [ { @@ -89,7 +89,7 @@ import { css, html, customElement, property } from '@umbraco-cms/backoffice/exte @customElement('my-sectionview-element') export class MySectionViewElement extends UmbLitElement { - render() { + override render() { return html` Sectionview content goes here @@ -97,7 +97,7 @@ export class MySectionViewElement extends UmbLitElement { ` } - static override styles = [ + static override readonly styles = [ css` :host { display: block; From 1cd8a9450d3fc583d5de0869182bf726ae7e187e Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Thu, 27 Mar 2025 11:18:14 +0100 Subject: [PATCH 08/13] docs: uses overflow="wrap" on large code sections --- .../tutorials/creating-a-custom-dashboard/README.md | 6 +++--- .../tutorials/creating-a-property-editor/README.md | 2 +- .../adding-configuration-to-a-property-editor.md | 2 +- .../integrating-context-with-a-property-editor.md | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/15/umbraco-cms/tutorials/creating-a-custom-dashboard/README.md b/15/umbraco-cms/tutorials/creating-a-custom-dashboard/README.md index f826a12e54d..d9ec54434ee 100644 --- a/15/umbraco-cms/tutorials/creating-a-custom-dashboard/README.md +++ b/15/umbraco-cms/tutorials/creating-a-custom-dashboard/README.md @@ -99,7 +99,7 @@ Now let's create the web component we need for our property editor. This web com 1. Create a file in the `src` folder with the name `welcome-dashboard.element.ts` 2. In this new file, add the following code: -{% code title="welcome-dashboard.element.ts" lineNumbers="true" %} +{% code title="welcome-dashboard.element.ts" lineNumbers="true" overflow="wrap" %} ```typescript import { LitElement, css, html, customElement } from "@umbraco-cms/backoffice/external/lit"; import { UmbLitElement } from "@umbraco-cms/backoffice/lit-element"; @@ -107,7 +107,7 @@ import { UmbLitElement } from "@umbraco-cms/backoffice/lit-element"; @customElement('my-welcome-dashboard') export class MyWelcomeDashboardElement extends UmbLitElement { - render() { + override render() { return html`

Welcome Dashboard

@@ -120,7 +120,7 @@ export class MyWelcomeDashboardElement extends UmbLitElement { `; } - static styles = [ + static override readonly styles = [ css` :host { display: block; diff --git a/15/umbraco-cms/tutorials/creating-a-property-editor/README.md b/15/umbraco-cms/tutorials/creating-a-property-editor/README.md index f3c400b44fe..6dc0fbb9cbf 100644 --- a/15/umbraco-cms/tutorials/creating-a-property-editor/README.md +++ b/15/umbraco-cms/tutorials/creating-a-property-editor/README.md @@ -399,7 +399,7 @@ override render() { See the entire file: suggestions-property-editor-ui.element.ts -{% code title="suggestions-property-editor-ui.element.ts" lineNumbers="true" %} +{% code title="suggestions-property-editor-ui.element.ts" lineNumbers="true" overflow="wrap" %} ```typescript import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; import { css, customElement, html, LitElement, property, state } from '@umbraco-cms/backoffice/external/lit'; diff --git a/15/umbraco-cms/tutorials/creating-a-property-editor/adding-configuration-to-a-property-editor.md b/15/umbraco-cms/tutorials/creating-a-property-editor/adding-configuration-to-a-property-editor.md index 4b733818e44..a0a609d9cbc 100644 --- a/15/umbraco-cms/tutorials/creating-a-property-editor/adding-configuration-to-a-property-editor.md +++ b/15/umbraco-cms/tutorials/creating-a-property-editor/adding-configuration-to-a-property-editor.md @@ -264,7 +264,7 @@ import { ifDefined } from "@umbraco-cms/backoffice/external/lit"; See the entire file: suggestions-property-editor-ui.element.ts -{% code title="suggestions-property-editor-ui.element.ts" lineNumbers="true" %} +{% code title="suggestions-property-editor-ui.element.ts" lineNumbers="true" overflow="wrap" %} ```typescript import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; import { css, customElement, html, ifDefined, LitElement, property, state } from '@umbraco-cms/backoffice/external/lit'; diff --git a/15/umbraco-cms/tutorials/creating-a-property-editor/integrating-context-with-a-property-editor.md b/15/umbraco-cms/tutorials/creating-a-property-editor/integrating-context-with-a-property-editor.md index b3cafebc503..c412ec61efb 100644 --- a/15/umbraco-cms/tutorials/creating-a-property-editor/integrating-context-with-a-property-editor.md +++ b/15/umbraco-cms/tutorials/creating-a-property-editor/integrating-context-with-a-property-editor.md @@ -176,7 +176,7 @@ constructor() { See the entire file: suggestions-property-editor-ui.element.ts -{% code title="suggestions-property-editor-ui.element.ts" lineNumbers="true" %} +{% code title="suggestions-property-editor-ui.element.ts" lineNumbers="true" overflow="wrap" %} ```typescript import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api'; import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; From 399d600d12ccb4e8d860526ffbf7b6ab7201b60d Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Thu, 27 Mar 2025 11:24:01 +0100 Subject: [PATCH 09/13] docs: shorten sentence --- 15/umbraco-cms/tutorials/creating-a-property-editor/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/15/umbraco-cms/tutorials/creating-a-property-editor/README.md b/15/umbraco-cms/tutorials/creating-a-property-editor/README.md index 6dc0fbb9cbf..b92012ede6f 100644 --- a/15/umbraco-cms/tutorials/creating-a-property-editor/README.md +++ b/15/umbraco-cms/tutorials/creating-a-property-editor/README.md @@ -16,7 +16,7 @@ The steps we will go through in part one are: * [Adding styling and setting up events in Web Components](./#adding-styling-and-setting-up-events-in-the-web-components) * [Setup Event Logic](./#setup-event-logic) -This tutorial uses TypeScript and Lit with Umbraco, It is expected that your package is already [set up to use TypeScript and Lit](../../customizing/development-flow/vite-package-setup.md). +This tutorial uses TypeScript and Lit with Umbraco. It is expected that your package is already [set up to use TypeScript and Lit](../../customizing/development-flow/vite-package-setup.md). To see how to set up an extension in Umbraco using TypeScript and Lit, read the article [Creating your first extension](../creating-your-first-extension.md). From e14a29b68ab5012a881903f907cb59e5b0f6ef18 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Thu, 27 Mar 2025 11:24:05 +0100 Subject: [PATCH 10/13] docs: vale --- .../property-editors/composition/property-editor-ui.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/15/umbraco-cms/customizing/property-editors/composition/property-editor-ui.md b/15/umbraco-cms/customizing/property-editors/composition/property-editor-ui.md index 5822c1ab107..4e1a61ece4c 100644 --- a/15/umbraco-cms/customizing/property-editors/composition/property-editor-ui.md +++ b/15/umbraco-cms/customizing/property-editors/composition/property-editor-ui.md @@ -89,7 +89,7 @@ interface UmbPropertyEditorUiElement extends HTMLElement { ``` {% hint style="info" %} -The `UmbPropertyEditorUiElement` interface is a TypeScript interface that ensures that your Element has the necessary properties and methods to be used as a Property Editor UI Element. See the [UI API Docs](https://apidocs.umbraco.com/v15/ui-api/interfaces/packages_core_property-editor.UmbPropertyEditorUiElement.html) for more information. +The `UmbPropertyEditorUiElement` interface is a TypeScript interface that ensures that your Element has the necessary properties and methods to be used as a Property Editor UI Element. See the [UI API documentation](https://apidocs.umbraco.com/v15/ui-api/interfaces/packages_core_property-editor.UmbPropertyEditorUiElement.html) for more information. {% endhint %} **Example with LitElement** From 193069532ad1a0e0f408791d44925bd824ce1879 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Thu, 27 Mar 2025 11:27:48 +0100 Subject: [PATCH 11/13] docs(copilot advice): reformat code examples --- .../extending-overview/extension-types/menu.md | 2 +- .../extension-types/modals/custom-modals.md | 14 +++++++------- .../extension-types/sections/section-view.md | 4 ++-- .../creating-a-custom-dashboard/README.md | 4 ++-- .../tutorials/creating-a-property-editor/README.md | 10 +++++----- .../adding-configuration-to-a-property-editor.md | 4 ++-- .../integrating-context-with-a-property-editor.md | 2 +- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/15/umbraco-cms/customizing/extending-overview/extension-types/menu.md b/15/umbraco-cms/customizing/extending-overview/extension-types/menu.md index 2209b21685e..e305a7b8155 100644 --- a/15/umbraco-cms/customizing/extending-overview/extension-types/menu.md +++ b/15/umbraco-cms/customizing/extending-overview/extension-types/menu.md @@ -36,7 +36,7 @@ The manifest can also be written in TypeScript. For this TypeScript example we used a [Backoffice Entry Point](../../extending-overview/extension-types/backoffice-entry-point.md) extension to register the manifests. ```typescript -import type { ManifestMenu } from "@umbraco-cms/backoffice/menu"; +import type { ManifestMenu } from '@umbraco-cms/backoffice/menu'; const menuManifest: Array = [ { diff --git a/15/umbraco-cms/customizing/extending-overview/extension-types/modals/custom-modals.md b/15/umbraco-cms/customizing/extending-overview/extension-types/modals/custom-modals.md index 4698f64ed0a..0beb8fb0fb7 100644 --- a/15/umbraco-cms/customizing/extending-overview/extension-types/modals/custom-modals.md +++ b/15/umbraco-cms/customizing/extending-overview/extension-types/modals/custom-modals.md @@ -20,7 +20,7 @@ There are two parts to creating a custom modal: A modal token is a string that identifies a modal. This is the modal extension alias. It is used to open a modal and is also to set default options for the modal. It should also have a unique alias to avoid conflicts with other modals. ```ts -import { UmbModalToken } from "@umbraco-cms/backoffice/modal"; +import { UmbModalToken } from '@umbraco-cms/backoffice/modal'; export type MyModalData = { headline: string; @@ -48,10 +48,10 @@ Additionally, the modal element can see its data parameters through the `modalCo {% code title="my-modal.element.ts" %} ```ts -import { html, LitElement, property, customElement } from "@umbraco-cms/backoffice/external/lit"; -import { UmbElementMixin } from "@umbraco-cms/backoffice/element-api"; -import { type UmbModalContext, UmbModalExtensionElement } from "@umbraco-cms/backoffice/modal"; -import type { MyModalData, MyModalValue } from "./my-modal.token.ts"; +import { html, LitElement, property, customElement } from '@umbraco-cms/backoffice/external/lit'; +import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api'; +import { type UmbModalContext, UmbModalExtensionElement } from '@umbraco-cms/backoffice/modal'; +import type { MyModalData, MyModalValue } from './my-modal.token.js'; @customElement('my-dialog') export default class MyDialogElement @@ -69,14 +69,14 @@ export default class MyDialogElement } private _handleSubmit() { - this.modalContext?.updateValue({ myData: "hello world" }); + this.modalContext?.updateValue({ myData: 'hello world' }); this.modalContext?.submit(); } render() { return html`
-

${this.modalContext?.data.headline ?? "Default headline"}

+

${this.modalContext?.data.headline ?? 'Default headline'}

diff --git a/15/umbraco-cms/customizing/extending-overview/extension-types/sections/section-view.md b/15/umbraco-cms/customizing/extending-overview/extension-types/sections/section-view.md index 6ee280adb83..39be2284a63 100644 --- a/15/umbraco-cms/customizing/extending-overview/extension-types/sections/section-view.md +++ b/15/umbraco-cms/customizing/extending-overview/extension-types/sections/section-view.md @@ -51,7 +51,7 @@ The manifest can also be written in TypeScript. For this TypeScript example we used a [Backoffice Entry Point](../backoffice-entry-point.md) extension to register the manifests. ```typescript -import { ManifestSectionView } from "@umbraco-cms/backoffice/section"; +import { ManifestSectionView } from '@umbraco-cms/backoffice/section'; const sectionViews: Array = [ { @@ -83,7 +83,7 @@ Creating the Section View Element using a Lit Element. **my-section.element.ts:** ```typescript -import { UmbLitElement } from "@umbraco-cms/backoffice/lit-element"; +import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { css, html, customElement, property } from '@umbraco-cms/backoffice/external/lit'; @customElement('my-sectionview-element') diff --git a/15/umbraco-cms/tutorials/creating-a-custom-dashboard/README.md b/15/umbraco-cms/tutorials/creating-a-custom-dashboard/README.md index d9ec54434ee..b647ef69f7c 100644 --- a/15/umbraco-cms/tutorials/creating-a-custom-dashboard/README.md +++ b/15/umbraco-cms/tutorials/creating-a-custom-dashboard/README.md @@ -101,8 +101,8 @@ Now let's create the web component we need for our property editor. This web com {% code title="welcome-dashboard.element.ts" lineNumbers="true" overflow="wrap" %} ```typescript -import { LitElement, css, html, customElement } from "@umbraco-cms/backoffice/external/lit"; -import { UmbLitElement } from "@umbraco-cms/backoffice/lit-element"; +import { LitElement, css, html, customElement } from '@umbraco-cms/backoffice/external/lit'; +import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; @customElement('my-welcome-dashboard') export class MyWelcomeDashboardElement extends UmbLitElement { diff --git a/15/umbraco-cms/tutorials/creating-a-property-editor/README.md b/15/umbraco-cms/tutorials/creating-a-property-editor/README.md index b92012ede6f..c02af2ed6ff 100644 --- a/15/umbraco-cms/tutorials/creating-a-property-editor/README.md +++ b/15/umbraco-cms/tutorials/creating-a-property-editor/README.md @@ -91,7 +91,7 @@ import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/propert @customElement('my-suggestions-property-editor-ui') export default class MySuggestionsPropertyEditorUIElement extends LitElement implements UmbPropertyEditorUiElement { @property({ type: String }) - public value = ""; + public value = ''; override render() { return html`I'm a property editor!`; @@ -218,14 +218,14 @@ It should now look something like this: {% code title="suggestions-property-editor-ui.element.ts" lineNumbers="true" %} ```typescript -import { LitElement, html, css, customElement, property } from "@umbraco-cms/backoffice/external/lit"; -import type { UmbPropertyEditorUiElement } from "@umbraco-cms/backoffice/property-editor"; +import { LitElement, html, css, customElement, property } from '@umbraco-cms/backoffice/external/lit'; +import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/property-editor'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; @customElement('my-suggestions-property-editor-ui') export default class MySuggestionsPropertyEditorUIElement extends LitElement implements UmbPropertyEditorUiElement { @property({ type: String }) - public value = ""; + public value = ''; override render() { return html` @@ -345,7 +345,7 @@ Let's look at the suggestions button next. {% code title="suggestions-property-editor-ui.element.ts" %} ```typescript -import { LitElement, html, css, customElement, property, state } from "@umbraco-cms/backoffice/external/lit"; +import { LitElement, html, css, customElement, property, state } from '@umbraco-cms/backoffice/external/lit'; ``` {% endcode %} diff --git a/15/umbraco-cms/tutorials/creating-a-property-editor/adding-configuration-to-a-property-editor.md b/15/umbraco-cms/tutorials/creating-a-property-editor/adding-configuration-to-a-property-editor.md index a0a609d9cbc..3d16ada5e02 100644 --- a/15/umbraco-cms/tutorials/creating-a-property-editor/adding-configuration-to-a-property-editor.md +++ b/15/umbraco-cms/tutorials/creating-a-property-editor/adding-configuration-to-a-property-editor.md @@ -192,7 +192,7 @@ The next step is to gain access to our new configuration options. For this, open {% code title="suggestions-property-editor-ui.element.ts" %} ```typescript -import { type UmbPropertyEditorConfigCollection } from "@umbraco-cms/backoffice/property-editor"; +import { type UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor'; ``` {% endcode %} @@ -215,7 +215,7 @@ We can now use the configurations. Let's use the `placeholder` and `maxChars` fo {% code title="suggestions-property-editor-ui.element.ts" %} ```typescript -import { ifDefined } from "@umbraco-cms/backoffice/external/lit"; +import { ifDefined } from '@umbraco-cms/backoffice/external/lit'; ``` {% endcode %} diff --git a/15/umbraco-cms/tutorials/creating-a-property-editor/integrating-context-with-a-property-editor.md b/15/umbraco-cms/tutorials/creating-a-property-editor/integrating-context-with-a-property-editor.md index c412ec61efb..3172349dba9 100644 --- a/15/umbraco-cms/tutorials/creating-a-property-editor/integrating-context-with-a-property-editor.md +++ b/15/umbraco-cms/tutorials/creating-a-property-editor/integrating-context-with-a-property-editor.md @@ -111,7 +111,7 @@ import { UMB_MODAL_MANAGER_CONTEXT, UMB_CONFIRM_MODAL,} from '@umbraco-cms/backo 2. Remove the `UmbNotificationContext` from the `'@umbraco-cms/backoffice/notification'` import: ```typescript -import { UMB_NOTIFICATION_CONTEXT, UmbNotificationDefaultData } from "@umbraco-cms/backoffice/notification"; +import { UMB_NOTIFICATION_CONTEXT, UmbNotificationDefaultData } from '@umbraco-cms/backoffice/notification'; ``` 3. Update the constructor to consume the `UMB_MODAL_MANAGER_CONTEXT`and the `UMB_CONFIRM_MODAL.` From d1b83823ea89e4b2fdb30ceec274560b73e329e5 Mon Sep 17 00:00:00 2001 From: Jacob Overgaard <752371+iOvergaard@users.noreply.github.com> Date: Thu, 27 Mar 2025 11:35:07 +0100 Subject: [PATCH 12/13] docs(vale): shortens a sentence --- .../property-editors/composition/property-editor-ui.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/15/umbraco-cms/customizing/property-editors/composition/property-editor-ui.md b/15/umbraco-cms/customizing/property-editors/composition/property-editor-ui.md index 4e1a61ece4c..b0b3c5c6624 100644 --- a/15/umbraco-cms/customizing/property-editors/composition/property-editor-ui.md +++ b/15/umbraco-cms/customizing/property-editors/composition/property-editor-ui.md @@ -89,7 +89,9 @@ interface UmbPropertyEditorUiElement extends HTMLElement { ``` {% hint style="info" %} -The `UmbPropertyEditorUiElement` interface is a TypeScript interface that ensures that your Element has the necessary properties and methods to be used as a Property Editor UI Element. See the [UI API documentation](https://apidocs.umbraco.com/v15/ui-api/interfaces/packages_core_property-editor.UmbPropertyEditorUiElement.html) for more information. +The `UmbPropertyEditorUiElement` interface ensures that your Element has the necessary properties and methods to be used as a Property Editor UI Element. + +See the [UI API documentation](https://apidocs.umbraco.com/v15/ui-api/interfaces/packages_core_property-editor.UmbPropertyEditorUiElement.html) for more information. {% endhint %} **Example with LitElement** From 6ee1c859f50747ec0904c959407d867ec4a3f065 Mon Sep 17 00:00:00 2001 From: leekelleher Date: Thu, 27 Mar 2025 15:12:51 +0000 Subject: [PATCH 13/13] Replaces `UmbElementMixin(LitElement)` with `UmbElementMixin` for simplification. --- .../extension-types/modals/custom-modals.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/15/umbraco-cms/customizing/extending-overview/extension-types/modals/custom-modals.md b/15/umbraco-cms/customizing/extending-overview/extension-types/modals/custom-modals.md index 0beb8fb0fb7..321382a9159 100644 --- a/15/umbraco-cms/customizing/extending-overview/extension-types/modals/custom-modals.md +++ b/15/umbraco-cms/customizing/extending-overview/extension-types/modals/custom-modals.md @@ -48,14 +48,15 @@ Additionally, the modal element can see its data parameters through the `modalCo {% code title="my-modal.element.ts" %} ```ts -import { html, LitElement, property, customElement } from '@umbraco-cms/backoffice/external/lit'; -import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api'; -import { type UmbModalContext, UmbModalExtensionElement } from '@umbraco-cms/backoffice/modal'; +import { customElement, html, property } from '@umbraco-cms/backoffice/external/lit'; +import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; +import { UmbModalExtensionElement } from '@umbraco-cms/backoffice/modal'; +import type { UmbModalContext } from '@umbraco-cms/backoffice/modal'; import type { MyModalData, MyModalValue } from './my-modal.token.js'; @customElement('my-dialog') export default class MyDialogElement - extends UmbElementMixin(LitElement) + extends UmbLitElement implements UmbModalExtensionElement { @property({ attribute: false }) @@ -105,13 +106,13 @@ To open the modal, you need to consume the `UmbModalManagerContext` and then use {% code title="my-element.ts" %} ```ts -import { MY_MODAL_TOKEN } from './my-modal.token'; +import { customElement, html } from '@umbraco-cms/backoffice/external/lit'; +import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; +import { MY_MODAL_TOKEN } from './my-modal.token.js'; import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; -import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api'; -import { LitElement, html, customElement } from '@umbraco-cms/backoffice/external/lit'; @customElement('my-element') -class MyElement extends UmbElementMixin(LitElement) { +class MyElement extends UmbLitElement { #modalManagerContext?: typeof UMB_MODAL_MANAGER_CONTEXT.TYPE; constructor() {