Home: Fix portlet broken by Shoelace update to 1.8

They made HasSlotController internal only
This commit is contained in:
nathan 2023-11-15 09:01:37 -07:00
parent 8814f55ff3
commit a9fcf05fab
2 changed files with 137 additions and 5 deletions

View File

@ -17,7 +17,7 @@ import type {InteractEvent} from "@interactjs/core/InteractEvent";
import {egw} from "../../jsapi/egw_global";
import {css, html, TemplateResult} from "lit";
import {classMap} from "lit/directives/class-map.js";
import type {HasSlotController} from "../../../../node_modules/@shoelace-style/shoelace/dist/internal/slot";
import {HasSlotController} from "../Et2Widget/slot";
import shoelace from "../Styles/shoelace";
import {Et2Dialog} from "../Et2Dialog/Et2Dialog";
import {et2_IResizeable} from "../et2_core_interfaces";
@ -81,8 +81,7 @@ export class Et2Portlet extends Et2Widget(SlCard)
font-size: var(--sl-font-size-medium);
line-height: var(--sl-line-height-dense);
padding: 0px;
padding-left: var(--header-spacing);
padding-right: calc(2em + var(--header-spacing));
padding-left: 0px;
margin: 0px;
position: relative;
}
@ -111,8 +110,12 @@ export class Et2Portlet extends Et2Widget(SlCard)
height: 100%
}
.card_header {
margin-right: calc(var(--sl-spacing-medium) + 1em);
.card__header {
display: flex;
width: 100%;
padding: 0px;
padding-left: var(--sl-spacing-medium);
padding-right: calc(2em + var(--header-spacing));
}
.card__body {

View File

@ -0,0 +1,129 @@
import type {ReactiveController, ReactiveControllerHost} from 'lit';
/**
* A reactive controller that determines when slots exist.
*
* Copied from Shoelace
* /src/internal/slot.ts
*/
export class HasSlotController implements ReactiveController
{
host : ReactiveControllerHost & Element;
slotNames : string[] = [];
constructor(host : ReactiveControllerHost & Element, ...slotNames : string[])
{
(this.host = host).addController(this);
this.slotNames = slotNames;
}
private hasDefaultSlot()
{
return [...this.host.childNodes].some(node =>
{
if(node.nodeType === node.TEXT_NODE && node.textContent!.trim() !== '')
{
return true;
}
if(node.nodeType === node.ELEMENT_NODE)
{
const el = node as HTMLElement;
const tagName = el.tagName.toLowerCase();
// Ignore visually hidden elements since they aren't rendered
if(tagName === 'sl-visually-hidden')
{
return false;
}
// If it doesn't have a slot attribute, it's part of the default slot
if(!el.hasAttribute('slot'))
{
return true;
}
}
return false;
});
}
private hasNamedSlot(name : string)
{
return this.host.querySelector(`:scope > [slot="${name}"]`) !== null;
}
test(slotName : string)
{
return slotName === '[default]' ? this.hasDefaultSlot() : this.hasNamedSlot(slotName);
}
hostConnected()
{
this.host.shadowRoot!.addEventListener('slotchange', this.handleSlotChange);
}
hostDisconnected()
{
this.host.shadowRoot!.removeEventListener('slotchange', this.handleSlotChange);
}
private handleSlotChange = (event : Event) =>
{
const slot = event.target as HTMLSlotElement;
if((this.slotNames.includes('[default]') && !slot.name) || (slot.name && this.slotNames.includes(slot.name)))
{
this.host.requestUpdate();
}
};
}
/**
* Given a slot, this function iterates over all of its assigned element and text nodes and returns the concatenated
* HTML as a string. This is useful because we can't use slot.innerHTML as an alternative.
*/
export function getInnerHTML(slot : HTMLSlotElement) : string
{
const nodes = slot.assignedNodes({flatten: true});
let html = '';
[...nodes].forEach(node =>
{
if(node.nodeType === Node.ELEMENT_NODE)
{
html += (node as HTMLElement).outerHTML;
}
if(node.nodeType === Node.TEXT_NODE)
{
html += node.textContent;
}
});
return html;
}
/**
* Given a slot, this function iterates over all of its assigned text nodes and returns the concatenated text as a
* string. This is useful because we can't use slot.textContent as an alternative.
*/
export function getTextContent(slot : HTMLSlotElement | undefined | null) : string
{
if(!slot)
{
return '';
}
const nodes = slot.assignedNodes({flatten: true});
let text = '';
[...nodes].forEach(node =>
{
if(node.nodeType === Node.TEXT_NODE)
{
text += node.textContent;
}
});
return text;
}