Skip to content

Commit

Permalink
improvement: fix slots edge cases (#417)
Browse files Browse the repository at this point in the history
  • Loading branch information
vladitasev authored May 21, 2019
1 parent e4907b9 commit 9e0c9aa
Showing 1 changed file with 45 additions and 44 deletions.
89 changes: 45 additions & 44 deletions packages/base/src/UI5Element.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,56 +176,31 @@ class UI5Element extends HTMLElement {
const autoIncrementMap = new Map();
domChildren.forEach(child => {
// Determine the type of the child (mainly by the slot attribute)
const childType = this._getChildType(child);
const slotName = this.constructor._getSlotName(child);

// Check if the childType is supported
if (slotsMap[childType] === undefined) {
// Check if the slotName is supported
if (slotsMap[slotName] === undefined) {
const validValues = Object.keys(slotsMap).join(", ");
console.warn(`Unknown childType: ${childType}, ignoring`, child, `Valid values are: ${validValues}`); // eslint-disable-line
console.warn(`Unknown slotName: ${slotName}, ignoring`, child, `Valid values are: ${validValues}`); // eslint-disable-line
return;
}

// For children that need individual slots, calculate them
if (slotsMap[childType].individualSlots) {
const nextId = (autoIncrementMap.get(childType) || 0) + 1;
autoIncrementMap.set(childType, nextId);
child._individualSlot = `${childType}-${nextId}`;
if (slotsMap[slotName].individualSlots) {
const nextId = (autoIncrementMap.get(slotName) || 0) + 1;
autoIncrementMap.set(slotName, nextId);
child._individualSlot = `${slotName}-${nextId}`;
}

// Distribute the child in the _state object
if (slotsMap[childType].multiple) {
this._state[childType] = [...this._state[childType], child];
if (slotsMap[slotName].multiple) {
this._state[slotName] = [...this._state[slotName], child];
} else {
this._state[childType] = child;
this._state[slotName] = child;
}
});
}

_getChildType(child) {
const defaultSlot = this.constructor.getMetadata().getDefaultSlot();

// Text nodes can only go to the default slot
if (!(child instanceof HTMLElement)) {
return defaultSlot;
}

// Check for explicitly given logical slot
const ui5Slot = child.getAttribute("data-ui5-slot");
if (ui5Slot) {
return ui5Slot;
}

// Discover the slot based on the real slot name (f.e. footer => footer, or content-32 => content)
const slot = child.getAttribute("slot");
if (slot) {
const match = slot.match(/^([^-]+)-\d+$/);
return match ? match[1] : slot;
}

// Use default slot as a fallback
return defaultSlot;
}

static get observedAttributes() {
const observedProps = this.getMetadata().getObservedProps();
return observedProps.map(camelToKebabCase);
Expand Down Expand Up @@ -363,7 +338,7 @@ class UI5Element extends HTMLElement {
_attachChildPropertyUpdated(child, propData) {
const listenFor = propData.listenFor,
childMetadata = child.constructor.getMetadata(),
childType = child.getAttribute("data-ui5-slot"), // all slotted children have the same configuration
slotName = this.constructor._getSlotName(child), // all slotted children have the same configuration
childProperties = childMetadata.getProperties();

let observedProps = [],
Expand All @@ -380,8 +355,8 @@ class UI5Element extends HTMLElement {
notObservedProps = Array.isArray(listenFor.exclude) ? listenFor.exclude : [];
}

if (!this._monitoredChildProps.has(childType)) {
this._monitoredChildProps.set(childType, { observedProps, notObservedProps });
if (!this._monitoredChildProps.has(slotName)) {
this._monitoredChildProps.set(slotName, { observedProps, notObservedProps });
}

child.addEventListener("_propertyChange", this._onChildPropertyUpdated);
Expand All @@ -396,7 +371,8 @@ class UI5Element extends HTMLElement {
return;
}

const propsMetadata = this.parentNode._monitoredChildProps.get(this.getAttribute("data-ui5-slot"));
const slotName = this.constructor._getSlotName(this);
const propsMetadata = this.parentNode._monitoredChildProps.get(slotName);

if (!propsMetadata) {
return;
Expand Down Expand Up @@ -451,7 +427,7 @@ class UI5Element extends HTMLElement {
const domChildren = Array.from(this.children);

domChildren.forEach(child => {
const childType = this._getChildType(child);
const slotName = this.constructor._getSlotName(child);
const slot = child.getAttribute("slot");
const hasSlot = !!slot;

Expand All @@ -463,17 +439,17 @@ class UI5Element extends HTMLElement {

// If the user set a slot equal to the default slot, f.e. slot="content", remove it
// Otherwise, stop here
if (childType === defaultSlot) {
if (slotName === defaultSlot) {
if (hasSlot) {
child.removeAttribute("slot");
}
return;
}

// Compatibility - for the ones with "data-ui5-slot"
// If they don't have a slot yet, and are not of the default child type, set childType as slot
// If they don't have a slot yet, and are not of the default child type, set slotName as slot
if (!hasSlot) {
child.setAttribute("slot", childType);
child.setAttribute("slot", slotName);
}
}, this);

Expand Down Expand Up @@ -621,6 +597,31 @@ class UI5Element extends HTMLElement {
return `__${className}${nextNumber}`;
}

static _getSlotName(child) {
const defaultSlot = this.getMetadata().getDefaultSlot();

// Text nodes can only go to the default slot
if (!(child instanceof HTMLElement)) {
return defaultSlot;
}

// Check for explicitly given logical slot
const ui5Slot = child.getAttribute("data-ui5-slot");
if (ui5Slot) {
return ui5Slot;
}

// Discover the slot based on the real slot name (f.e. footer => footer, or content-32 => content)
const slot = child.getAttribute("slot");
if (slot) {
const match = slot.match(/^(.+?)-\d+$/);
return match ? match[1] : slot;
}

// Use default slot as a fallback
return defaultSlot;
}

static generateAccessors() {
const proto = this.prototype;

Expand Down

0 comments on commit 9e0c9aa

Please sign in to comment.