+ *
+ *
+ * And the rest of content is added via `slots` getter by SlotMixin
+ * The function should move only content projection and ignore the rest
+ * */
+
+ source.innerHTML = `
+
+ ${variableNothing}
+
+ ${defaultSlottableProvidedViaSlotsGetter}
+
+ ${namedSlottable}
+ `;
+
+ moveUserProvidedDefaultSlottablesToTarget(source, target);
+ expect(target.children.length).to.equal(3);
+ const test1Element = target.querySelector('.test1');
+ const test2Element = target.querySelector('.test2');
+ const test3Element = target.querySelector('.test3');
+ expect(test1Element?.parentElement === target).to.equal(true);
+ expect(test2Element?.parentElement === target).to.equal(true);
+ expect(test3Element?.parentElement === target).to.equal(true);
+ });
+
describe('Rerender', () => {
it('supports rerender when SlotRerenderObject provided', async () => {
const tag = defineCE(
diff --git a/packages/ui/components/listbox/src/ListboxMixin.js b/packages/ui/components/listbox/src/ListboxMixin.js
index c609c0d48..6b2111435 100644
--- a/packages/ui/components/listbox/src/ListboxMixin.js
+++ b/packages/ui/components/listbox/src/ListboxMixin.js
@@ -4,6 +4,7 @@ import { dedupeMixin } from '@open-wc/dedupe-mixin';
import { ChoiceGroupMixin, FormControlMixin, FormRegistrarMixin } from '@lion/ui/form-core.js';
import { ScopedElementsMixin } from '../../core/src/ScopedElementsMixin.js';
import { LionOptions } from './LionOptions.js';
+import { moveUserProvidedDefaultSlottablesToTarget } from '../../core/src/SlotMixin.js';
// TODO: extract ListNavigationWithActiveDescendantMixin that can be reused in [role="menu"]
// having children with [role="menuitem|menuitemcheckbox|menuitemradio|option"] and
@@ -21,39 +22,6 @@ import { LionOptions } from './LionOptions.js';
// TODO: consider adding methods below to @lion/helpers
-/**
- * Sometimes, we want to provide best DX (direct slottables) and be accessible
- * at the same time.
- * In the first example below, we need to wrap our options in light dom in an element with
- * [role=listbox]. We could achieve this via the second example, but it would affect our
- * public api negatively. not allowing us to be forward compatible with the AOM spec:
- * https://wicg.github.io/aom/explainer.html
- * With this method, it's possible to watch elements in the default slot and move them
- * to the desired target (the element with [role=listbox]) in light dom.
- *
- * @example
- * # desired api
- *
- *
- *
- * # desired end state
- *
- *
- *
- *
- *
- * @param {HTMLElement} source host of ShadowRoot with default
- * @param {HTMLElement} target the desired target in light dom
- */
-function moveDefaultSlottablesToTarget(source, target) {
- Array.from(source.childNodes).forEach((/** @type {* & Element} */ c) => {
- const isNamedSlottable = c.hasAttribute && c.hasAttribute('slot');
- if (!isNamedSlottable) {
- target.appendChild(c);
- }
- });
-}
-
/**
* @type {ListboxMixin}
* @param {import('@open-wc/dedupe-mixin').Constructor} superclass
@@ -899,9 +867,9 @@ const ListboxMixinImplementation = superclass =>
);
if (slot) {
- moveDefaultSlottablesToTarget(this, this._listboxNode);
+ moveUserProvidedDefaultSlottablesToTarget(this, this._listboxNode);
slot.addEventListener('slotchange', () => {
- moveDefaultSlottablesToTarget(this, this._listboxNode);
+ moveUserProvidedDefaultSlottablesToTarget(this, this._listboxNode);
});
}
}
diff --git a/packages/ui/components/overlays/test/OverlayController.test.js b/packages/ui/components/overlays/test/OverlayController.test.js
index ff508a498..72b2d2afe 100644
--- a/packages/ui/components/overlays/test/OverlayController.test.js
+++ b/packages/ui/components/overlays/test/OverlayController.test.js
@@ -799,6 +799,9 @@ describe('OverlayController', () => {
const { parentOverlay, childOverlay } = await createNestedEscControllers(parentContent);
await mimicEscapePress(childOverlay.contentNode);
+ // without this line, the test is unstable on FF sometimes
+ await aTimeout(0);
+
expect(parentOverlay.isShown).to.be.false;
expect(childOverlay.isShown).to.be.true;