@webwriter/timeline
Version:
Create/learn with a digital timeline and test your knowledge.
89 lines (78 loc) • 3.08 kB
text/typescript
import { localized, msg } from "@lit/localize";
import { LitElementWw } from "@webwriter/lit";
import { css, html } from "lit";
import { customElement, state } from "lit/decorators.js";
import { classMap } from "lit/directives/class-map.js";
import LOCALIZE from "../../localization/generated";
/**
* The details of a `webwriter-timeline-event` component. Should not be used independently.
* As children, it can contain any HTML content representing the details of the event.
*/
()
("webwriter-timeline-event-details")
export class WebWriterTimelineEventDetailsWidget extends LitElementWw {
protected localize = LOCALIZE;
static styles = css`
:host {
position: relative;
word-break: break-word;
overflow-wrap: break-word;
overflow: hidden;
}
.hide {
display: none;
}
.show-placeholder::after {
content: var(--placeholder-text);
pointer-events: none;
position: absolute;
top: 0;
left: 0;
color: var(--sl-color-gray-500);
}
::slotted(iframe) {
box-sizing: border-box;
}
`;
()
private accessor isEmpty = false;
private observedElement: HTMLElement = null;
private mutationObserver = new MutationObserver(() => {
let empty = this.observedElement.childNodes.length === 0;
// If the only child is a trailing break, consider it empty
if (this.observedElement.children.length === 1) {
const child = this.observedElement.children[0];
empty = child.tagName === "BR" && child.classList.contains("ProseMirror-trailingBreak");
}
this.isEmpty = empty;
});
private handleSlotChange(event: Event) {
const assignedNodes = (event.target as HTMLSlotElement).assignedElements();
this.mutationObserver.disconnect();
if (assignedNodes.length === 1) {
// If the slot contains exactly one node, we need to check if it's empty,
// and observe it for changes.
this.observedElement = assignedNodes[0] as HTMLElement;
this.isEmpty = this.observedElement.textContent === "";
this.mutationObserver.observe(this.observedElement, { childList: true });
} else {
// If the slot contains more than one node, there is at least some content,
// so we don't need to show the placeholder.
this.isEmpty = false;
this.observedElement = null;
}
}
private get isInEditView() {
return this.contentEditable === "true" || this.contentEditable === "";
}
render() {
return html`<slot
style="--placeholder-text: '${msg("Details")}'"
class=${classMap({
"show-placeholder": this.isInEditView && this.isEmpty,
hide: !this.isInEditView && this.isEmpty,
})}
@slotchange=${this.handleSlotChange}
></slot>`;
}
}