Skip to content

Commit

Permalink
feat: cloned property to the slot decorator (#7882)
Browse files Browse the repository at this point in the history
`cloned` property should be set to true if the content of the
slot is being cloned to the static area. Common example is the valueStateMessage.

FIXES: #7681
  • Loading branch information
MapTo0 authored Nov 29, 2023
1 parent 10b78f4 commit 2f3742b
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 6 deletions.
9 changes: 6 additions & 3 deletions packages/base/src/UI5Element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,15 +255,18 @@ abstract class UI5Element extends HTMLElement {
*/
_startObservingDOMChildren() {
const ctor = this.constructor as typeof UI5Element;
const shouldObserveChildren = ctor.getMetadata().hasSlots();
const metadata = ctor.getMetadata();
const shouldObserveChildren = metadata.hasSlots();

if (!shouldObserveChildren) {
return;
}

const canSlotText = ctor.getMetadata().canSlotText();
const canSlotText = metadata.canSlotText();
const hasClonedSlot = Object.keys(metadata.getSlots()).some(slotName => metadata.getSlots()[slotName].cloned);
const mutationObserverOptions = {
childList: true,
subtree: canSlotText,
subtree: canSlotText || hasClonedSlot,
characterData: canSlotText,
};
observeDOMNode(this, this._processChildren.bind(this) as MutationCallback, mutationObserverOptions);
Expand Down
4 changes: 2 additions & 2 deletions packages/base/src/UI5ElementMetadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type Slot = {
propertyName?: string,
individualSlots?: boolean,
invalidateOnChildChange?: boolean | SlotInvalidation,
cloned?: boolean,
};

type SlotValue = Node;
Expand Down Expand Up @@ -185,8 +186,7 @@ class UI5ElementMetadata {
* @returns {boolean}
*/
canSlotText() {
const defaultSlot = this.getSlots().default;
return defaultSlot && defaultSlot.type === Node;
return (this.getSlots().default)?.type === Node;
}

/**
Expand Down
6 changes: 5 additions & 1 deletion packages/main/src/Input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -616,7 +616,11 @@ class Input extends UI5Element implements SuggestionComponent, IFormElement {
* @slot
* @public
*/
@slot()
@slot({
type: HTMLElement,
invalidateOnChildChange: true,
cloned: true,
})
valueStateMessage!: Array<HTMLElement>;

hasSuggestionItemSelected: boolean;
Expand Down
22 changes: 22 additions & 0 deletions packages/main/test/pages/Input.html
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,29 @@ <h3>Input - change event handling</h3>
<div>
Change event value: <span id="input-change-value-3"></span>
</div>

<br>

<ui5-input value-state="Error" id="dynamic-value-state">
<span slot="valueStateMessage" id="text">0</span>
</ui5-input>

<br>

<ui5-button id="dynamic-value-state-trigger">Trigger dynamic value state</ui5-button>

<script>
const dynamicValueState = document.getElementById("dynamic-value-state");
const dynamicValueStateTrigger = document.getElementById("dynamic-value-state-trigger");

dynamicValueStateTrigger.addEventListener("click", () => {
const valueState = dynamicValueState.querySelector("[slot='valueStateMessage']");

setInterval(() => {
valueState.textContent = parseInt(valueState.textContent) + 1;
}, 1000);
});

document.getElementById("submit-input").addEventListener("keypress", function(event) {
if (event.key === 'Enter') {
var formToSubmit = document.getElementById("submit-form");
Expand Down
20 changes: 20 additions & 0 deletions packages/main/test/specs/Input.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,26 @@ describe("Input general interaction", () => {
assert.ok(respPopover, "Responsive popover with valueStateMessage should be opened.");
});

it("Checks if valueStateMessage gets updated dynamically", async () => {
const btn = await $("#dynamic-value-state-trigger");
const input = await $("#dynamic-value-state").shadow$("input");

await input.scrollIntoView();
await btn.click();
await browser.pause(2000);
await input.click();

const staticAreaItemClassName = await browser.getStaticAreaItemClassName("#dynamic-value-state");
const valueStatePopover = await browser.$(`.${staticAreaItemClassName}`).shadow$("ui5-popover");
const initialContent = await valueStatePopover.$("[slot='valueStateMessage']").getHTML();

await browser.pause(2000);

const changedContent = await valueStatePopover.$("[slot='valueStateMessage']").getHTML();

assert.notEqual(initialContent, changedContent, "Content of the slot should be cloned when changed");
});

it("Checks if aria-describedby is renderd if not neccessary", async () => {
const input = await browser.$("#input-max-length"); // Input with no show-suggestions attribute
const innerInput = await input.shadow$("input");
Expand Down

0 comments on commit 2f3742b

Please sign in to comment.