Skip to content

Commit

Permalink
fix(ui/core): rerender direct host child with right slot attr when ro…
Browse files Browse the repository at this point in the history
…ot is switched
  • Loading branch information
tlouisse committed Jan 16, 2025
1 parent 43b694e commit 066dd23
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .changeset/great-pumas-rush.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@lion/ui': patch
---

[core] rerender direct host child with right slot attr when root is switched
13 changes: 13 additions & 0 deletions packages/ui/components/core/src/SlotMixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,19 @@ const SlotMixinImplementation = superclass =>
// Providing all options breaks Safari: we keep host and creationScope
const { creationScope, host } = this.renderOptions;
render(template, rerenderTarget, { creationScope, host, renderBefore });

// Assume we had: { 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...
// However, when myBool changes to false, the <span id=b></span> would be rendered instead...
// We need to make sure that this "replaced root" gets the slot applied as well
const isRerenderingRootOfTemplate =
renderAsDirectHostChild &&
renderBefore.previousElementSibling &&
!renderBefore.previousElementSibling.slot;

if (isRerenderingRootOfTemplate) {
renderBefore.previousElementSibling.slot = slotName;
}
}

/**
Expand Down
50 changes: 50 additions & 0 deletions packages/ui/components/core/test/SlotMixin.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,56 @@ describe('SlotMixin', () => {
expect(isActiveElement(el._focusableNode._buttonNode, { deep: true })).to.be.true;
});

it('allows for switching template 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-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-node"></slot>`;
}

get _myNode() {
return /** @type HTMLSpanElement */ (
Array.from(this.children).find(elm => elm.slot === 'my-node')
);
}
},
);
const el = /** @type {* & SlotHost} */ (await fixture(`<${tagName}></${tagName}>`));

expect(el._myNode.id).to.equal('is-not-switched');
expect(el.innerHTML).to.equal(
`<!--_start_slot_my-node_--><!----><span id="is-not-switched" slot="my-node"> </span> <!--_end_slot_my-node_-->`,
);

el.isSwitched = true;
await el.updateComplete;

expect(el._myNode.id).to.equal('is-switched');
expect(el.innerHTML).to.equal(
`<!--_start_slot_my-node_--><!----><div id="is-switched" slot="my-node"></div><!--_end_slot_my-node_-->`,
);
});

describe('firstRenderOnConnected (for backwards compatibility)', () => {
it('does render on connected when firstRenderOnConnected:true', async () => {
// Start with elem that does not render on connectedCallback
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ export class LionInputTelDropdown extends LionInputTel {

return {
template: templates.dropdown(this._templateDataDropdown),
renderAsDirectHostChild: Boolean,
renderAsDirectHostChild: true,
};
},
};
Expand Down

0 comments on commit 066dd23

Please sign in to comment.