Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
- Pages no longer show breadcrumbs when the only one would be the current page, such as the Dashboard. ([#20612](https://github.com/craftcms/cms/pull/20612))
- Fields’ translation indicators now show their descriptions when pressed, including on touch devices, rather than on hover. ([#20612](https://github.com/craftcms/cms/pull/20612))
- Fixed a bug where focus was lost after choosing elements in a relation field’s selector modal, or canceling it. Focus now returns to the field’s add button, or to the chosen element when the field is full. ([#20653](https://github.com/craftcms/cms/pull/20653))
- Fixed a bug where focus was lost after choosing elements in an element select input that became full, such as one in a plugin’s settings, rather than moving to the last element’s action menu. ([#20659](https://github.com/craftcms/cms/pull/20659))
- Fixed a bug where typing in fields, especially Markdown fields, lagged on entries with many fields. ([#20637](https://github.com/craftcms/cms/issues/20637))
- Fixed a bug where the user menu showed a “Permissions” item on Craft Solo, which led to a 403 error. ([#20621](https://github.com/craftcms/cms/issues/20621), [#20635](https://github.com/craftcms/cms/pull/20635))
- Fixed a bug where control panel forms could show the wrong fields after a failed save, such as the Base URL field on a new site whose “This site has its own base URL” setting was turned off. ([#20632](https://github.com/craftcms/cms/pull/20632), [#20636](https://github.com/craftcms/cms/pull/20636))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,16 @@ it('reads its chips and hides Add once the limit is reached', () => {
expect(addButton().classList.contains('hidden')).toBe(true);
});

it("moves focus to the last chip's action menu once the field is full", () => {
const input = boot({limit: 2});
const invoker = input
.getElementById(2)!
.querySelector('craft-action-menu > [slot="invoker"]');

expect(invoker).not.toBeNull();
expect(input.getNextLogicalFocusElement()).toBe(invoker);
});

it('removes a chip from the value and frees its slot', async () => {
const input = boot({limit: 2});
const change = vi.fn();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,10 @@ export class BaseElementSelectInput extends Base<BaseElementSelectInputSettings>
}

getLastActionBtn(): HTMLElement | null {
const buttons = this.container.querySelectorAll<HTMLElement>('.action-btn');
// A chip's `craft-action-menu` invoker, or an old disclosure menu trigger
const buttons = this.container.querySelectorAll<HTMLElement>(
'craft-action-menu > [slot="invoker"], .action-btn'
);
return buttons[buttons.length - 1] ?? null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,26 @@ it("moves elements from their reorder buttons' menus", () => {
);
});

it("moves focus to the last chip's action menu once the field is full", () => {
class UninitializedElementSelectInput extends BaseElementSelectInput {}

const input = new UninitializedElementSelectInput();
const chip = (id: number) =>
`<li><div class="element chip" data-id="${id}"><div slot="suffix"><craft-action-menu><craft-button slot="invoker"></craft-button><div slot="content"></div></craft-action-menu></div></div></li>`;
const container = document.createElement('div');
container.innerHTML = `<ul class="elements">${chip(1)}${chip(2)}</ul>`;
input.$container = jquery(container);
input.$elements = input.$container.find('.element');
input.settings = {allowAdd: true, limit: 2} as BaseElementSelectInputSettings;

const $focusTarget = input.getNextLogicalFocusElement();

expect($focusTarget.length).toBe(1);
expect($focusTarget[0]).toBe(
container.querySelector('[data-id="2"] [slot="invoker"]')
);
});

/**
* An instance with just enough stubbed to observe the order of
* `onModalSelect()`'s side effects — the real method wants jQuery, garnish and
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,10 @@ export class BaseElementSelectInput extends Base<BaseElementSelectInputSettings>
}

getLastActionBtn(): any {
return this.$container.find('.action-btn').last();
// A chip's `craft-action-menu` invoker, or an old disclosure menu trigger
return this.$container
.find('craft-action-menu > [slot="invoker"], .action-btn')
.last();
}

focusLastActionBtn(): void {
Expand Down