From 4901e0496f7a066d20e74ee0ddcd95cb34e1a874 Mon Sep 17 00:00:00 2001 From: Jacob Welander Jensen <64834767+Welander1994@users.noreply.github.com> Date: Thu, 30 Oct 2025 15:06:04 +0100 Subject: [PATCH 1/3] working on a auto closing ... modal when focus leaves --- .../entity-action/entity-action-list.element.ts | 7 +++++++ .../entity-actions-dropdown.element.ts | 16 ++++++++++++++-- .../appsettings.Development.template.json | 6 ++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/entity-action-list.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/entity-action-list.element.ts index 17b15475c1a8..cdfaf6806043 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/entity-action-list.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/entity-action-list.element.ts @@ -59,6 +59,13 @@ export class UmbEntityActionListElement extends UmbLitElement { }; } + override focus() { + console.log("focusing first menu item"); + const firstMenuItem = this.renderRoot.querySelector('uui-menu-item'); + console.log(firstMenuItem); + (firstMenuItem?.shadowRoot?.querySelector('#label-button') as any)?.focus(); + }; + #hasRenderedOnce?: boolean; override render() { return this._filter diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/global-components/entity-actions-dropdown/entity-actions-dropdown.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/global-components/entity-actions-dropdown/entity-actions-dropdown.element.ts index 7c5d4da98cd5..e81c435730d8 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/global-components/entity-actions-dropdown/entity-actions-dropdown.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/global-components/entity-actions-dropdown/entity-actions-dropdown.element.ts @@ -1,6 +1,6 @@ import type { UmbDropdownElement } from '../../../components/dropdown/index.js'; import { UmbEntityActionListElement } from '../../entity-action-list.element.js'; -import { html, customElement, property, css, query } from '@umbraco-cms/backoffice/external/lit'; +import { html, customElement, property, css, query, nothing } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { UUIScrollContainerElement } from '@umbraco-cms/backoffice/external/uui'; import { UMB_ENTITY_CONTEXT, type UmbEntityModel } from '@umbraco-cms/backoffice/entity'; @@ -49,7 +49,14 @@ export class UmbEntityActionsDropdownElement extends UmbLitElement { #onDropdownOpened() { if (this.#scrollContainerElement) { - return; // Already created + this.#entityActionListElement = undefined; + this.#scrollContainerElement.remove(); + this.#scrollContainerElement = undefined; + } + + if (this.#entityActionListElement) { + this.#entityActionListElement?.focus(); + return; } // First create dropdown content when the dropdown is opened. @@ -64,11 +71,16 @@ export class UmbEntityActionsDropdownElement extends UmbLitElement { this._dropdownElement?.appendChild(this.#scrollContainerElement); } + override render() { return html` + !['umb-entity-action-list', 'uui-scroll-container'].includes((e.relatedTarget as HTMLElement)?.tagName.toLowerCase() || '') + && this.#onActionExecuted() + } .label=${this.label} ?compact=${this.compact} hide-expand> diff --git a/src/Umbraco.Web.UI/appsettings.Development.template.json b/src/Umbraco.Web.UI/appsettings.Development.template.json index 5b8bc438a94e..f5a5089e6f8e 100644 --- a/src/Umbraco.Web.UI/appsettings.Development.template.json +++ b/src/Umbraco.Web.UI/appsettings.Development.template.json @@ -25,6 +25,12 @@ }, "Umbraco": { "CMS": { + "Security":{ + "BackOfficeHost": "http://localhost:5173", + "AuthorizeCallbackPathName": "/oauth_complete", + "AuthorizeCallbackLogoutPathName": "/logout", + "AuthorizeCallbackErrorPathName": "/error", + }, "Examine": { "LuceneDirectoryFactory": "TempFileSystemDirectoryFactory" }, From 32a79dc1aa6bf6ebc15bf6aacde1b1b69e0c16c7 Mon Sep 17 00:00:00 2001 From: Jacob Welander Jensen <64834767+Welander1994@users.noreply.github.com> Date: Fri, 31 Oct 2025 09:59:12 +0100 Subject: [PATCH 2/3] remove appsetting for local development --- src/Umbraco.Web.UI/appsettings.Development.template.json | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/Umbraco.Web.UI/appsettings.Development.template.json b/src/Umbraco.Web.UI/appsettings.Development.template.json index f5a5089e6f8e..e28da3a1029d 100644 --- a/src/Umbraco.Web.UI/appsettings.Development.template.json +++ b/src/Umbraco.Web.UI/appsettings.Development.template.json @@ -24,13 +24,7 @@ ] }, "Umbraco": { - "CMS": { - "Security":{ - "BackOfficeHost": "http://localhost:5173", - "AuthorizeCallbackPathName": "/oauth_complete", - "AuthorizeCallbackLogoutPathName": "/logout", - "AuthorizeCallbackErrorPathName": "/error", - }, + "CMS": "Examine": { "LuceneDirectoryFactory": "TempFileSystemDirectoryFactory" }, From 5725264da61829fd4921d721b5a52c09fe673d54 Mon Sep 17 00:00:00 2001 From: Jacob Welander Jensen <64834767+Welander1994@users.noreply.github.com> Date: Fri, 31 Oct 2025 11:26:13 +0100 Subject: [PATCH 3/3] rewrites the focus function to check if the shadow dom exsits before trying to set focus --- .../entity-action-list.element.ts | 29 +++++++++++++++---- .../entity-actions-dropdown.element.ts | 8 +---- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/entity-action-list.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/entity-action-list.element.ts index cdfaf6806043..ac55ab9857b0 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/entity-action-list.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/entity-action-list.element.ts @@ -59,12 +59,29 @@ export class UmbEntityActionListElement extends UmbLitElement { }; } - override focus() { - console.log("focusing first menu item"); - const firstMenuItem = this.renderRoot.querySelector('uui-menu-item'); - console.log(firstMenuItem); - (firstMenuItem?.shadowRoot?.querySelector('#label-button') as any)?.focus(); - }; + + +override focus() { + const extensionComponent = this.renderRoot.querySelector('umb-extension-with-api-slot'); + if (!extensionComponent) return; + + // Wait for the slot component to render + extensionComponent.updateComplete.then(() => { + const firstEntityAction = extensionComponent.shadowRoot?.querySelector('umb-entity-action'); + if (!firstEntityAction) return; + + firstEntityAction.updateComplete.then(() => { + const firstMenuItem = firstEntityAction.shadowRoot?.querySelector('uui-menu-item'); + + firstMenuItem?.updateComplete?.then(() => { + const labelButton = firstMenuItem.shadowRoot?.querySelector('#label-button') as HTMLElement; + labelButton?.focus(); + }); + }); + }); +} + + #hasRenderedOnce?: boolean; override render() { diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/global-components/entity-actions-dropdown/entity-actions-dropdown.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/global-components/entity-actions-dropdown/entity-actions-dropdown.element.ts index e81c435730d8..801e7b9f7952 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/global-components/entity-actions-dropdown/entity-actions-dropdown.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/global-components/entity-actions-dropdown/entity-actions-dropdown.element.ts @@ -48,14 +48,8 @@ export class UmbEntityActionsDropdownElement extends UmbLitElement { } #onDropdownOpened() { - if (this.#scrollContainerElement) { - this.#entityActionListElement = undefined; - this.#scrollContainerElement.remove(); - this.#scrollContainerElement = undefined; - } - if (this.#entityActionListElement) { - this.#entityActionListElement?.focus(); + this.#entityActionListElement.focus(); return; }