DEV: various improvements to d-menu (#26970)

- adds a `@groupIdentifier` property which will ensure that two menus of the same group are not expanded at the same time
- adds a `@class` property which will be applied to the trigger and the content
- adds a `@triggerClass` property which will be applied to the trigger
- adds a `@contentClass` property which will be applied to the trigger
- removes `extraClassName`
This commit is contained in:
Joffrey JAFFEUX 2024-05-10 13:43:37 +02:00 committed by GitHub
parent 46371fe9e4
commit 47cabdc6d2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 78 additions and 8 deletions

View File

@ -278,4 +278,63 @@ module("Integration | Component | FloatKit | d-menu", function (hooks) {
assert.dom(".fk-d-menu__content.test-content").doesNotExist();
});
test("opening a menu with the same identifier", async function (assert) {
await render(
hbs`<DMenu @inline={{true}} @identifier="foo" @class="first">1</DMenu><DMenu @inline={{true}} @identifier="foo" @class="second">2</DMenu>`
);
await click(".first.fk-d-menu__trigger");
assert.dom(".foo-content.first").exists();
assert.dom(".foo-content.second").doesNotExist();
await click(".second.fk-d-menu__trigger");
assert.dom(".foo-content.first").doesNotExist();
assert.dom(".foo-content.second").exists();
});
test("@groupIdentifier", async function (assert) {
await render(
hbs`<DMenu @inline={{true}} @groupIdentifier="foo" @class="first">1</DMenu><DMenu @inline={{true}} @groupIdentifier="foo" @class="second">2</DMenu>`
);
await click(".first.fk-d-menu__trigger");
assert.dom(".fk-d-menu__content.first").exists();
assert.dom(".fk-d-menu__content.second").doesNotExist();
await click(".second.fk-d-menu__trigger");
assert.dom(".fk-d-menu__content.first").doesNotExist();
assert.dom(".fk-d-menu__content.second").exists();
});
test("@class", async function (assert) {
await render(hbs`<DMenu @inline={{true}} @class="first">1</DMenu>`);
await open();
assert.dom(".fk-d-menu__trigger.first").exists();
assert.dom(".fk-d-menu__content.first").exists();
});
test("@triggerClass", async function (assert) {
await render(hbs`<DMenu @inline={{true}} @triggerClass="first">1</DMenu>`);
await open();
assert.dom(".fk-d-menu__trigger.first").exists();
assert.dom(".fk-d-menu__content.first").doesNotExist();
});
test("@contentClass", async function (assert) {
await render(hbs`<DMenu @inline={{true}} @contentClass="first">1</DMenu>`);
await open();
assert.dom(".fk-d-menu__trigger.first").doesNotExist();
assert.dom(".fk-d-menu__content.first").exists();
});
});

View File

@ -59,7 +59,6 @@ export default class DFloatBody extends Component {
@mainClass
(if this.options.animated "-animated")
(if @instance.expanded "-expanded")
this.options.extraClassName
}}
data-identifier={{this.options.identifier}}
data-content

View File

@ -58,6 +58,7 @@ export default class DMenu extends Component {
(if this.menuInstance.expanded "-expanded")
(concat this.options.identifier "-trigger")
@triggerClass
@class
}}
id={{this.menuInstance.id}}
data-identifier={{this.options.identifier}}
@ -83,6 +84,8 @@ export default class DMenu extends Component {
class={{concatClass
"fk-d-menu-modal"
(concat this.options.identifier "-content")
@contentClass
@class
}}
@inline={{(isTesting)}}
data-identifier={{@instance.options.identifier}}
@ -109,6 +112,8 @@ export default class DMenu extends Component {
"fk-d-menu"
"fk-d-menu__content"
(concat this.options.identifier "-content")
@class
@contentClass
}}
@innerClass="fk-d-menu__inner-content"
@role="dialog"

View File

@ -65,12 +65,15 @@ export const MENU = {
fallbackPlacements: FLOAT_UI_PLACEMENTS,
autoUpdate: true,
trapTab: true,
extraClassName: null,
onClose: null,
onShow: null,
onRegisterApi: null,
modalForMobile: false,
inline: null,
groupIdentifier: null,
triggerClass: null,
contentClass: null,
class: null,
},
portalOutletId: "d-menu-portal-outlet",
};

View File

@ -20,7 +20,9 @@ export default class Menu extends Service {
* @param {Object} [options.data] - An object which will be passed as the `@data` argument when content is a `Component`
* @param {Boolean} [options.arrow] - Determines if the menu has an arrow
* @param {Boolean} [options.offset] - Displaces the content from its reference trigger in pixels
* @param {String} [options.identifier] - Add a data-identifier attribute to the trigger and the content
* @param {String} [options.identifier] - Add a data-identifier attribute to the trigger and the content, multiple menus can have the same identifier,
* only one menu with the same identifier can be open at a time
* @param {String} [options.groupIdentifier] - Only one menu with the same groupIdentifier can be open at a time
* @param {Boolean} [options.inline] - Improves positioning for trigger that spans over multiple lines
*
* @returns {Promise<DMenuInstance>}
@ -47,13 +49,15 @@ export default class Menu extends Service {
}
}
if (instance.options.identifier) {
for (const menu of this.registeredMenus) {
if (instance.options.identifier || instance.options.groupIdentifier) {
for (const registeredMenu of this.registeredMenus) {
if (
menu.options.identifier === instance.options.identifier &&
menu !== instance
(registeredMenu.options.identifier === instance.options.identifier ||
registeredMenu.options.groupIdentifier ===
instance.options.groupIdentifier) &&
registeredMenu !== instance
) {
await this.close(menu);
await this.close(registeredMenu);
}
}
}