@oslokommune/punkt-elements
Version:
Komponentbiblioteket til Punkt, et designsystem laget av Oslo Origo
129 lines (128 loc) • 4.96 kB
TypeScript
import { LitElement } from 'lit';
import { AsyncDirective, PartInfo } from 'lit/async-directive.js';
import { ChildPart } from 'lit/directive.js';
/**
* Returns the SlotManager for a host, creating one if it doesn't exist.
* Call this in connectedCallback() to eagerly collect children before Lit renders.
*/
export declare function getSlotManager(host: LitElement): SlotManager;
/**
* Per-host singleton that manages node collection and observation.
* Scans host children, categorizes them by slot attribute, and notifies
* registered directives when children change.
*
* IMPORTANT: collectNodes() must be called BEFORE Lit's first render
* (typically in connectedCallback via PktElement.hasSlotContent or getSlotManager).
* Lit's first render clears host children, so collecting during render is too late.
*/
export declare class SlotManager {
private host;
private observer;
private nodesBySlot;
private directives;
private observing;
private trackedNodes;
generation: number;
private initialCollectionDone;
private processingMutations;
private placeholderToNode;
private nodeToPlaceholder;
private static PLACEHOLDER_PREFIX;
constructor(host: LitElement);
/**
* Collect original children BEFORE Lit's first render.
* Must be called in connectedCallback or earlier.
* Safe to call multiple times — only the first call scans.
*/
collectNodes(): void;
/**
* Register a directive instance and start observing for dynamic changes.
*/
addDirective(d: SlotContentDirective): void;
/**
* Unregister a directive instance. Stops observing if no directives remain.
*/
removeDirective(d: SlotContentDirective): void;
/**
* Returns nodes matching the given slot name.
*/
getNodes(slotName?: string): Node[];
/**
* Returns whether the given slot has any content.
*/
hasContent(slotName?: string): boolean;
/**
* Ensure a placeholder comment exists for a node that is about to be distributed.
* Called by the directive before Lit moves the node to the target position.
* The placeholder stays between Lit's ChildPart markers so that when the parent
* template conditionally removes the content, the MutationObserver can detect
* the placeholder removal and clean up the real node.
*/
ensurePlaceholder(node: Node): void;
/**
* Start MutationObserver for dynamic child changes.
* Deferred via setTimeout to avoid catching Lit's first render mutations.
*/
private startObserving;
private stopObserving;
/**
* Handle MutationObserver mutations incrementally.
* Only processes nodes that are NOT already part of Lit's rendered template.
*
* Uses a guard flag to prevent recursive handling: when notifyDirectives()
* causes setValue() to move nodes (e.g., from host into a ChildPart container),
* that move triggers another mutation which must be ignored.
*/
private handleMutations;
/**
* Determines if a node is user-provided content (not Lit's rendered template).
* Lit's rendered content includes comment markers and elements created by the template.
*/
private isUserContent;
private removeFromSlots;
private notifyDirectives;
}
/**
* AsyncDirective that renders slot content at its position in a Lit template.
*
* Usage:
* html`<div>${slotContent(this)}</div>` // default slot
* html`<div>${slotContent(this, 'helptext')}</div>` // named slot
*/
declare class SlotContentDirective extends AsyncDirective {
private manager;
private slotName;
private lastGeneration;
constructor(partInfo: PartInfo);
render(_host: LitElement, _slotName?: string): unknown;
update(_part: ChildPart, [host, slotName]: [LitElement, string?]): unknown;
/**
* Called by SlotManager when child mutations are detected.
* Uses setValue() to push an async update to Lit.
*/
handleNodesChanged(): void;
/**
* Insert placeholders for nodes that are still direct children of the host.
* Must be called before Lit moves them to the target position.
*/
private ensurePlaceholders;
disconnected(): void;
reconnected(): void;
private getNodesOrNoChange;
}
/**
* Directive that distributes Light DOM children into Lit template positions,
* functioning like Shadow DOM slots but without a shadow root.
*
* @param host - The component instance (typically `this`)
* @param slotName - Optional slot name. Omit for the default slot.
*
* @example
* // Default slot
* html`<div class="content">${slotContent(this)}</div>`
*
* // Named slot
* html`<div class="help">${slotContent(this, 'helptext')}</div>`
*/
export declare const slotContent: (_host: LitElement, _slotName?: string | undefined) => import('lit-html/directive.js').DirectiveResult<typeof SlotContentDirective>;
export {};