fix(ui/core): rerender direct host child with right slot attr when root is switched
This commit is contained in:
parent
81e2a1d2d1
commit
5344fdeb66
4 changed files with 71 additions and 1 deletions
5
.changeset/great-pumas-rush.md
Normal file
5
.changeset/great-pumas-rush.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'@lion/ui': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
[core] rerender direct host child with right slot attr when root is switched
|
||||||
|
|
@ -182,6 +182,21 @@ const SlotMixinImplementation = superclass =>
|
||||||
// Providing all options breaks Safari: we keep host and creationScope
|
// Providing all options breaks Safari: we keep host and creationScope
|
||||||
const { creationScope, host } = this.renderOptions;
|
const { creationScope, host } = this.renderOptions;
|
||||||
render(template, rerenderTarget, { creationScope, host, renderBefore });
|
render(template, rerenderTarget, { creationScope, host, renderBefore });
|
||||||
|
|
||||||
|
// Assume we had this config:
|
||||||
|
// `'my-slot': () => ({ template: myBool ? html`<div id=a></div>` : html`<span id=b></span>`, renderAsDirectHostChild: true })`
|
||||||
|
// If myBool started as true, <div id=a></div> would be rendered in first render above, a slot would be applied,
|
||||||
|
// resulting in <div id=a slot=my-slot></div>
|
||||||
|
// However, when myBool changes to false, the <span id=b></span> would be rendered as root instead...
|
||||||
|
// We need to make sure that this "replaced root" gets the slot applied as well => <span id=b slot=my-slot></span>
|
||||||
|
const isRerenderingRootOfTemplate =
|
||||||
|
renderAsDirectHostChild &&
|
||||||
|
renderBefore.previousElementSibling &&
|
||||||
|
!renderBefore.previousElementSibling.slot;
|
||||||
|
|
||||||
|
if (isRerenderingRootOfTemplate) {
|
||||||
|
renderBefore.previousElementSibling.slot = slotName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -345,6 +345,56 @@ describe('SlotMixin', () => {
|
||||||
expect(isActiveElement(el._focusableNode._buttonNode, { deep: true })).to.be.true;
|
expect(isActiveElement(el._focusableNode._buttonNode, { deep: true })).to.be.true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('allows for switching template root in slot as a direct child', async () => {
|
||||||
|
const tagName = defineCE(
|
||||||
|
// @ts-expect-error
|
||||||
|
class extends SlotMixin(LitElement) {
|
||||||
|
static properties = { isSwitched: Boolean };
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.isSwitched = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
get slots() {
|
||||||
|
return {
|
||||||
|
...super.slots,
|
||||||
|
'my-root-switcher-node': () => ({
|
||||||
|
template: this.isSwitched
|
||||||
|
? html`<div id="is-switched"></div>`
|
||||||
|
: html`<span id="is-not-switched"> </span> `,
|
||||||
|
renderAsDirectHostChild: true,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return html`<slot name="my-root-switcher-node"></slot>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
get _myRootSwitcherNode() {
|
||||||
|
return /** @type HTMLSpanElement */ (
|
||||||
|
Array.from(this.children).find(elm => elm.slot === 'my-root-switcher-node')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const el = /** @type {* & SlotHost} */ (await fixture(`<${tagName}></${tagName}>`));
|
||||||
|
|
||||||
|
expect(el._myRootSwitcherNode.id).to.equal('is-not-switched');
|
||||||
|
expect(el.innerHTML).to.equal(
|
||||||
|
`<!--_start_slot_my-root-switcher-node_--><!----><span id="is-not-switched" slot="my-root-switcher-node"> </span> <!--_end_slot_my-root-switcher-node_-->`,
|
||||||
|
);
|
||||||
|
|
||||||
|
el.isSwitched = true;
|
||||||
|
await el.updateComplete;
|
||||||
|
|
||||||
|
expect(el._myRootSwitcherNode.id).to.equal('is-switched');
|
||||||
|
expect(el.innerHTML).to.equal(
|
||||||
|
`<!--_start_slot_my-root-switcher-node_--><!----><div id="is-switched" slot="my-root-switcher-node"></div><!--_end_slot_my-root-switcher-node_-->`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
describe('firstRenderOnConnected (for backwards compatibility)', () => {
|
describe('firstRenderOnConnected (for backwards compatibility)', () => {
|
||||||
it('does render on connected when firstRenderOnConnected:true', async () => {
|
it('does render on connected when firstRenderOnConnected:true', async () => {
|
||||||
// Start with elem that does not render on connectedCallback
|
// Start with elem that does not render on connectedCallback
|
||||||
|
|
|
||||||
|
|
@ -181,7 +181,7 @@ export class LionInputTelDropdown extends LionInputTel {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
template: templates.dropdown(this._templateDataDropdown),
|
template: templates.dropdown(this._templateDataDropdown),
|
||||||
renderAsDirectHostChild: Boolean,
|
renderAsDirectHostChild: true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue