import type{LyraEventDetailSnapshot}from'../../../internal/lyra-element.js';import{type PropertyValues,type TemplateResult}from'lit';import{LyraElement}from'../../../internal/lyra-element.js';import type{LyraNodeTypeStyle}from'../../../internal/node-type-style.js';export type{LyraNodeTypeStyle}from'../../../internal/node-type-style.js';import type{LyraGraphCommunity,LyraGraphFit,LyraGraphNodeLabelsMode,LyraGraphRenderer,LyraGraphLink,LyraGraphNode}from'../graph/graph.class.js';import type{LyraEntity}from'../entity-card/entity-card.class.js';import type{LyraPathElement}from'../path-strip/path-strip.class.js';export type{LyraPathElement}from'../path-strip/path-strip.class.js';import'../graph/graph.class.js';import'../graph-legend/graph-legend.class.js';import'../entity-card/entity-card.class.js';import'../neighbor-list/neighbor-list.class.js';import'../path-strip/path-strip.class.js';import'../../overlays/overlay/popover.class.js';import'../../forms/input/input.class.js';import'../../overlays/chip/chip.class.js';import'../../forms/button/button.class.js'; /** Extra `LyraEntity` fields a plain `LyraGraphNode` doesn't carry -- merged in by node id to build * the entity shown in the details popover and neighbor rows. A node with no entry here still * renders fine: `degree` falls back to a live count derived from `links`, `description`/ * `properties` are simply omitted. */ export type LyraKnowledgeGraphEntityDetails=Pick; /** What drives ``'s own `dimmedNodeIds`/`dimmedLinkIds` forwarding, on * top of the always-active search-match dimming -- see `highlight`'s own doc comment. */ export type KnowledgeGraphHighlight='selection'|'hover'|'none';export interface LyraKnowledgeGraphExplorerEventMap{ /** The explorer changed its self-managed selection. Fires after `selectedNodeId` is updated for * search, graph, neighbor, path, entity-card, invalidation, and popover-close paths. Direct * host assignments remain silent. */ 'lr-selection-change':CustomEvent<{selectedNodeId:string|null;}>; /** The user asked to find a path between the two currently pinned nodes (the "Find path" action, * only rendered once exactly two nodes are pinned). `detail: { sourceNodeId, targetNodeId }` -- this * component has no graph-traversal algorithm of its own (client-side, backend call, whatever the * host prefers); it only requests one. The host computes/fetches the path and assigns the result * back through `path`. */ 'lr-path-request':CustomEvent<{sourceNodeId:string;targetNodeId:string;}>; /** A node's pinned state changed by user interaction. `detail: { pinnedNodeIds }` -- the complete * updated array. This component already toggles its own `pinnedNodeIds` copy before emitting * (the same self-toggle-then-emit contract `lr-graph-legend`'s `hiddenTypes`/`lr-visibility- * change` already establishes), so reassigning it back is optional -- useful only for a host * that wants to persist or observe pins elsewhere. */ 'lr-pin-change':CustomEvent>; /** The user typed in the toolbar's search box. `detail: { query, matchCount, matchCountExact }` * -- `query` is the canonical `LyraSearchChangeDetail` field name * (`internal/text-viewer-target.ts`). `matchCount` is the same live node-filter total the * search-result list and its own live-region announcement already compute (`0` while `query` * is empty). `matchCountExact` is always `true`: unlike a paginated text-search viewer, this * component's node filter has no ceiling, so it can never truncate. This is a live node * FILTER, not a cursor-based text search -- it deliberately never carries the canonical * `activeIndex` field, since it has no `searchNext`/`searchPrevious` active-match cursor to * report. The component has already applied the query to its own `searchQuery` before * emitting, the same self-toggle-then-emit contract `lr-pin-change` follows, so reassigning it * back is optional and a direct host assignment stays silent. */ 'lr-search-change':CustomEvent<{query:string;matchCount:number;matchCountExact:boolean;}>; /** A node type's visibility changed via the composed legend. `detail: { hiddenTypes }` -- the * complete updated array. This component already applies it to its own `hiddenTypes` before * emitting, the same self-toggle-then-emit contract `lr-pin-change`/`lr-search-change` follow, * so reassigning it back is optional and a direct host assignment stays silent. */ 'lr-hidden-types-change':CustomEvent>;'lr-node-click':CustomEvent<{nodeId:string;x:number;y:number;}>;'lr-link-click':CustomEvent<{sourceNodeId:string;targetNodeId:string;linkId?:string;}>;'lr-node-expand':CustomEvent<{nodeId:string;}>;'lr-community-click':CustomEvent<{communityId:string;}>;'lr-relation-activate':CustomEvent<{relation:string;sourceNodeId?:string;targetNodeId?:string;occurrenceIndex:number;}>;} /** * `` — an orchestration-level surface for exploring a knowledge * graph: the `lr-graph` canvas plus entity search, type filters, neighborhood expansion, pinned * nodes, path finding between pins, node selection, and a details overlay. Composes existing * primitives rather than re-implementing graph rendering: `lr-graph` (canvas/pan-zoom/selection), * `lr-graph-legend` (type filters), `lr-entity-card` (the details popover's default content), * `lr-neighbor-list` (the selected entity's relationships), `lr-path-strip` (a found path), and * `lr-popover.showAt()` (the details overlay itself). * * **How the details popover finds its viewport position.** `lr-graph.getNodePosition()` and the * `lr-node-click` event's `{ x, y }` are in the graph's own *local drawing space* (pre pan/zoom), * never viewport pixels -- passing them straight to `showAt()` would anchor the popover at the * wrong place as soon as the graph has panned or zoomed even once. A direct node click resolves * the correct viewport rect the way this library's own documented `lr-graph` + `lr-popover.showAt()` * composition does: for `renderer="svg"` (the default), `event.composedPath()` (the native `click` * that bubbles out of `lr-graph`'s shadow root) locates the actual clicked `[part="node"]` element, * whose `getBoundingClientRect()` is already viewport-relative; for `renderer="canvas"` (no * per-node DOM element to find), the click event's own `clientX`/`clientY` are used directly, since * canvas hit-testing already treats those as viewport coordinates internally. While the popover * stays open after an `renderer="svg"` click, this component re-reads that same resolved node * element's `getBoundingClientRect()` and re-calls `showAt()` every time the composed `lr-graph` * emits its own `lr-viewport-change` (a frame-coalesced pan/zoom/simulation-tick signal) -- * schedules no continuous popover-polling loop of its own, unlike an idle popover polling the DOM * every frame regardless of whether anything actually moved. Selecting a node any other * way -- a search result, a neighbor row, a path-strip element, keyboard Enter/Space on a graph * node (which never dispatches a native `click`) -- has no click event to read a rect from, so it * instead calls the public `lr-graph.focusNode(id)` (which centers that node in the viewport) and * then anchors the popover at the graph element's own `getBoundingClientRect()` center once that * settles; no continuous tracking applies to that path. * * **Controlled vs. self-managed state.** `nodes`/`links`/`nodeTypes`/`communities`/`entityDetails`/ * `path` are purely host-supplied data, rendered as given. `hiddenTypes`/`selectedNodeId`/ * `searchQuery`/`pinnedNodeIds` are this component's own genuinely new contribution: it wires them * into `lr-graph`'s existing controlled props (`hiddenTypes`, `selectedNodeIds`, `dimmedNodeIds`, * `dimmedLinkIds`) itself, toggling its own copy on interaction (the same self-toggle-then-emit * contract `lr-graph-legend` already uses) so every feature works with zero host wiring, while * still being presettable/observable properties and emitting events (`lr-selection-change`, * `lr-pin-change`, `lr-path-request`, plus every composed primitive's own event bubbling straight through * unmodified) for a host that wants to persist or react to them. * Hidden node types are excluded from both search matches and selected-entity neighbor rows, and * activation requests for a hidden node are ignored before selection changes. * * `highlight` controls what drives that dimming, on top of the always-active search-match * dimming: `'selection'` (the default) dims by the selected node's immediate neighborhood; * `'hover'` also dims by whichever node is currently pointer-hovered (falling back to the selected * node's neighborhood while nothing is hovered); `'none'` turns this component's own dimming off * entirely, forwarding empty `dimmedNodeIds`/`dimmedLinkIds` regardless of search/selection state * -- for a host that wants to drive `lr-graph`'s dimming through a different composition instead. * * Public collection properties take bounded, clone-owned readonly snapshots. Create a new * collection and reassign it after changes; mutating the assigned array does not update the view. * * @customElement lr-knowledge-graph-explorer * @slot details - Overrides the details popover's default content (an `lr-entity-card` with a * nested `lr-neighbor-list` and a pin toggle). Receives no data -- a consumer overriding this * slot reads the selected entity from `selectedNodeId`/`nodes` itself. Replaces the default * card entirely, including `detail-body`/`detail-actions` below. * @slot detail-body - Additive content appended inside the default `lr-entity-card`'s body, * alongside its `lr-neighbor-list`. No effect while `details` is overridden. * @slot detail-actions - Additive content appended into the default `lr-entity-card`'s `actions` * slot, beside its built-in pin toggle. No effect while `details` is overridden. * @event lr-selection-change - The explorer changed its self-managed selection. `detail: * { selectedNodeId: string | null }`. Direct host assignments do not emit. * @event lr-path-request - `detail: { sourceNodeId, targetNodeId }`. See the class doc above. * @event lr-pin-change - `detail: { pinnedNodeIds }`. See the class doc above. * @event lr-search-change - The user typed in the toolbar's search box. `detail: * { query, matchCount, matchCountExact }`. `query` is the canonical `LyraSearchChangeDetail` * name; `matchCountExact` is always `true` since this component's node filter has no truncating * ceiling. No `activeIndex` -- this is a live node filter, not a cursor-based search. * Direct host assignments do not emit. * @event lr-hidden-types-change - A node type's visibility changed via the composed legend. * `detail: { hiddenTypes }`. See the class doc above. Direct host assignments do not emit. * @event lr-node-click - Bubbles straight through from the composed `lr-graph`, unmodified. * @event lr-link-click - Bubbles straight through from the composed `lr-graph`, unmodified. * @event lr-node-expand - Bubbles straight through from `lr-graph` and/or `lr-neighbor-list` (the * same event name/detail shape from either source) -- this component never appends neighbors * itself, only forwards the request; a host fetches/generates the expansion and assigns updated * `nodes`/`links` back. * @event lr-community-click - Bubbles straight through from the composed `lr-graph`, unmodified. * @event lr-relation-activate - Bubbles straight through from the composed `lr-path-strip`, unmodified. * @csspart base - The root wrapper. It owns `role="group"` and the fallback name unless a * non-empty host `aria-label` makes the host the sole overall owner. * @csspart toolbar - The row wrapping the search input and the type-filter legend. * @csspart search - The composed `lr-entity-card` search `lr-input`. * @csspart legend - The composed `lr-graph-legend`. * @csspart search-results - The search-match list, only rendered while `searchQuery` is non-empty. * @csspart search-result - One search-match row (`role="listitem"`, wrapping a `