import type{LyraEventDetailSnapshot}from'../../../internal/lyra-element.js';import{type TemplateResult,type PropertyValues}from'lit';import{LyraElement}from'../../../internal/lyra-element.js';import{type FormOwnerValue}from'../../../internal/form-associated.js'; /** Traversal direction relative to the matched node(s): `'out'` (outgoing edges), `'in'` * (incoming edges), or `'both'`. */ export type GraphQueryDirection='out'|'in'|'both'; /** One pickable relationship or node type, as offered to this component's type pickers via * `relationshipTypeOptions`/`nodeTypeOptions`. */ export interface GraphQueryTypeOption{readonly value:string; /** Display label. Falls back to `value` when omitted. */ readonly label?:string;} /** * The serializable query model this component builds and edits -- a single typed relationship/ * path filter over a knowledge graph, suitable for handing directly to a GraphRAG retrieval or * traversal backend. `startId`/`endId` anchor the path (`endId` left empty means "any reachable * node" rather than a specific target); `relationshipTypes`/`nodeTypes` constrain which edges/ * nodes the traversal may pass through (empty arrays mean "any type"); `direction` constrains * edge traversal direction; `minHops`/`maxHops` bound the path length, mirroring a graph query * language's variable-length path syntax (e.g. Cypher's `-[:REL*1..3]->`). * * This is deliberately a **flat** shape, not a nested boolean filter tree: a GraphRAG relationship * -path query composes by union ("traverse `worksFor` OR `foundedBy`, through `Person` or * `Organization` nodes, 1 to 3 hops out from this entity") rather than by nested AND/OR groups -- * every array field here is implicitly OR'd, and there is exactly one path per query. A branching * multi-path/subgraph-pattern query is a different, considerably heavier feature and out of scope. */ export interface GraphQuery{ /** The anchor entity id the traversal starts from. Required for the query to be valid/runnable * -- see `checkValidity()`. */ readonly startId:string; /** An optional specific target entity id ("find a path to this node"). Empty means any * reachable node satisfying the other filters. */ readonly endId:string; /** Relationship (edge) type values to traverse. Empty means any relationship type. */ readonly relationshipTypes:readonly string[]; /** Node type values the traversal may pass through. Empty means any node type. */ readonly nodeTypes:readonly string[];readonly direction:GraphQueryDirection; /** Minimum path length, inclusive. */ readonly minHops:number; /** Maximum path length, inclusive. Must be `>= minHops` -- see `checkValidity()`. */ readonly maxHops:number;} /** One named, host-persisted query. `id` is assigned by the host (e.g. on `lr-query-save`) -- * this component never generates ids itself, the same controlled-list convention every other * Lyra component with a host-owned collection follows. */ export interface GraphQuerySavedItem{readonly id:string;readonly name:string;readonly query:GraphQuery;} /** Frozen payload shared by the run request and accepted notification. */ export interface GraphQueryRunDetail{readonly query:GraphQuery;} /** Frozen payload shared by the save request and accepted notification. */ export interface GraphQuerySaveDetail{readonly name:string;readonly query:GraphQuery;} /** Frozen payload shared by the load request and accepted notification. */ export interface GraphQueryLoadDetail{readonly queryId:string;readonly query:GraphQuery;} /** Frozen payload shared by the delete request and accepted notification. */ export interface GraphQueryDeleteDetail{readonly queryId:string;}export interface LyraGraphQueryBuilderEventMap{'lr-invalid':CustomEvent;'lr-input':CustomEvent>;'lr-validity-change':CustomEvent<{readonly valid:boolean;readonly errors:Readonly>;}>;'lr-before-query-run':CustomEvent>;'lr-query-run':CustomEvent>;'lr-before-query-save':CustomEvent>;'lr-query-save':CustomEvent>;'lr-before-query-load':CustomEvent>;'lr-query-load':CustomEvent>;'lr-before-query-delete':CustomEvent;'lr-query-delete':CustomEvent;} /** * `` — an editor for a single typed relationship/path filter * (`GraphQuery`) over a knowledge graph: start/end entity anchors, relationship-type and * node-type pickers with a removable active-filter chip display, a traversal direction, a * min/max hop range, validation, and a host-persisted saved-query list -- a serializable query * model for GraphRAG workflows (feed the `value`/`lr-query-run` payload straight to a retrieval * or traversal backend). * * Composes `` for every closed-choice picker (relationship type, node type, * direction, hop counts) and `` for the free-text entity ids -- the relationship/ * node-type pickers are "add" selects: choosing an option appends it to the corresponding * array and the picker itself resets to its placeholder, so the *current* selection is shown * separately as a row of removable ``s inside an `` (click a chip's * remove button to drop that one type). A type value present in `value` but missing from * `relationshipTypeOptions`/`nodeTypeOptions` (e.g. a saved query referencing a type that was * since renamed/removed from the picker's own option list) still renders as a chip, labeled with * its raw value, rather than being silently dropped. * Removing a focused filter chip moves focus to its adjacent survivor or the matching add picker. * When the host applies a focused saved-query deletion, focus follows the adjacent delete action * or the stable save-name input; unrelated controlled updates never steal external focus. * * **Query model placement:** `GraphQuery` is kept local to this component rather than promoted * to the shared `src/ai/types.ts` surface. Unlike that module's types (`ChatMessage`, * `Citation`, `RetrievalQuery`, etc.), which each mirror a shape multiple existing primitives * already consume, `GraphQuery` is specific to this component's own editable-filter-set shape * (its `minHops`/`maxHops` selects, its "add picker + chip list" editing idiom) -- no other * component reads or produces this exact shape today. This mirrors ``'s * `RubricValue`/`RubricKey` and ``'s `ToolParamFormSchema`, both also kept * local to their own component for the identical reason. * * **Form association:** every other "structured, non-string value" editor in this package that * looks like this one -- ``, ``, `` -- attaches * `ElementInternals` directly (the `FormAssociated` mixin only fits a plain string value) and * treats native `
` participation as a nice-to-have layered on top of its primary * `value`/`lr-input`/`lr-validity-change` integration contract, not a requirement. This component * follows that same established convention: `value` round-trips through `JSON.stringify()` as the * submitted form value, and a consumer that never places this inside a `` loses nothing. * The normalized initial `value` is captured as the reset default; `form.reset()` restores that * model, clears interaction/touched state and the save-name draft, and preserves a caller-set * custom validity message like a native control. * The start-entity input carries native `required`, matching the aggregate builder's * `valueMissing` rule. Host `focus()`/`click()` reach the first rendered field, and `blur()` * releases whichever nested field owns deep focus. * An unavailable DOM focus getter skips restoration without preventing chip removal or saved-query * updates. Ordinary focused removal still follows the adjacent control and leaves outside focus alone. * * Run, save, load, and delete use the same two-phase action contract: a cancelable * `lr-before-query-*` request precedes any local effect, followed by a non-cancelable * `lr-query-*` accepted notification. Vetoing a request suppresses its accepted notification; * for save it also preserves the draft name, and for load it preserves the current `value`. * * **Accessible name:** a host-level `aria-label` wins. Otherwise the region (`role="group"`) is * labelled by the same visible label element that renders the `label` slot/property/localized * default, so visible and announced names cannot diverge. The same region carries explicit * `aria-invalid="true"|"false"` from the complete builder's effective intrinsic/custom validity. * * @customElement lr-graph-query-builder * @slot actions - Extra host controls rendered in the footer beside the Run button. * @slot label - Visible label for the complete form control. * @slot hint - Supporting text for the complete form control. * @slot error - Error text for the complete form control. * @event lr-input - `detail: { value }` — any field changed; the full current query. Hop select * choices emit it once; child native/prefixed value and listbox lifecycle aliases are contained. * @event lr-validity-change - Frozen `detail: { valid, errors }` from effective native validity, * including custom errors and validation barring; fired only on an actual change. * @event lr-before-query-run - Cancelable request emitted after `reportValidity()` passes, before * accepting Run. Frozen `detail: { query }`; vetoing it suppresses `lr-query-run`. * @event lr-query-run - Non-cancelable accepted Run notification. Frozen `detail: { query }`. * @event lr-before-query-save - Cancelable save request with frozen `detail: { name, query }`. * Vetoing it preserves the draft name and suppresses `lr-query-save`. * @event lr-query-save - Non-cancelable accepted Save notification. Frozen * `detail: { name, query }`; the host assigns an id and appends to `savedQueries`. * @event lr-before-query-load - Cancelable load request with frozen `detail: { queryId, query }`, * emitted before `value` changes. Vetoing it preserves the current query. * @event lr-query-load - Non-cancelable accepted Load notification emitted after `value` changes. * Frozen `detail: { queryId, query }` contains the accepted query. * @event lr-before-query-delete - Cancelable delete request with frozen `detail: { queryId }`. * Vetoing it suppresses `lr-query-delete`. * @event lr-query-delete - Non-cancelable accepted Delete notification. Frozen * `detail: { queryId }`; the host removes the matching entry from `savedQueries`. * @event lr-invalid - Cancelable alias when the complete builder fails native validity; vetoing it * also suppresses the native invalid default. * @csspart base - The outer wrapper around every section. * @csspart label - Visible label for the complete form control. * @csspart hint - Supporting text for the complete form control. * @csspart error - Error text for the complete form control. * @csspart path-fields - The row wrapping the start/end entity inputs and hop-count selects. * @csspart start-input - The start-entity ``. * @csspart end-input - The end-entity ``. * @csspart min-hops - The minimum-hops ``. * @csspart max-hops - The maximum-hops ``. * @csspart filter-group - One type-filter section (relationship or node type); rendered twice. * @csspart relationship-picker - The "add a relationship type" ``. * @csspart relationship-chips - The `` listing currently active relationship types. * @csspart node-type-picker - The "add a node type" ``. * @csspart node-type-chips - The `` listing currently active node types. * @csspart direction - The traversal-direction ``. * @csspart footer - The row containing the actions slot and the Run button. * @csspart run-button - The Run button. * @csspart saved-queries - The wrapper around the save row and the saved-query list. * @csspart saved-queries-label - The saved-queries section heading. * @csspart save-row - The row containing the save-name input and Save button. * @csspart save-name-input - The new-saved-query name ``. * @csspart save-button - The Save button. * @csspart saved-empty - The message shown when `savedQueries` has no entries. * @csspart saved-list - The list of saved queries. * @csspart saved-item - One saved query's row. * @csspart saved-load-button - A saved query row's Load button. * @csspart saved-delete-button - A saved query row's delete button. * @cssprop [--lr-graph-query-builder-run-bg=var(--lr-color-brand)] - Run button resting background. * @cssprop [--lr-graph-query-builder-run-border-color=var(--lr-color-brand)] - Run button resting border color. * @cssprop [--lr-graph-query-builder-run-color=var(--lr-color-on-brand)] - Run button resting foreground. * @cssprop --lr-graph-query-builder-run-hover-bg - Run button hover background; defaults to the * current brand hover mix. * @cssprop --lr-graph-query-builder-run-active-bg - Run button pressed background; defaults to the * current brand active mix. * @cssprop [--lr-graph-query-builder-save-bg=var(--lr-color-surface)] - Save button resting background. * @cssprop [--lr-graph-query-builder-save-border-color=var(--lr-color-border)] - Save button resting border color. * @cssprop [--lr-graph-query-builder-save-color=var(--lr-color-text)] - Save button resting foreground. * @cssprop [--lr-graph-query-builder-save-hover-bg=var(--lr-color-brand-quiet)] - Save button hover background. * @cssprop --lr-graph-query-builder-save-active-bg - Save button pressed background; defaults to * the current quiet-brand active mix. * @cssprop [--lr-graph-query-builder-saved-load-color=var(--lr-color-text)] - Saved-query Load button foreground. * @cssprop --lr-graph-query-builder-saved-load-active-bg - Saved-query Load button pressed * background; defaults to the current surface active mix. * @cssprop [--lr-graph-query-builder-saved-delete-color=var(--lr-color-text-quiet)] - Saved-query delete foreground. * @cssprop [--lr-graph-query-builder-saved-delete-hover-color=var(--lr-color-danger)] - Saved-query delete hover foreground. * @cssprop --lr-graph-query-builder-saved-delete-active-color - Saved-query delete pressed * foreground; defaults to the current danger active mix. * @cssprop [--lr-graph-query-builder-saved-delete-active-bg=var(--lr-color-danger-quiet)] - Saved-query delete pressed background. * @cssstate required - Always matches. This control's one constraint is unconditional — a query * with no start anchor is not runnable — so it always demands something of the user, which is what * `lr-graph-query-builder:state(required)` asks. * @cssstate optional - Never matches, for the same reason: the complement of `required`. * @cssstate valid - Matches while the query satisfies both constraints (a non-empty `startId` and * `minHops <= maxHops`), whether or not the user has touched anything. * @cssstate invalid - Matches while it does not — from the very first render, before any * interaction, since an empty query has no start anchor. * @cssstate user-valid - `valid`, and the user has interacted: an edit to any field, a blur of * the start-entity input, `reportValidity()` (what the Run button runs), or a submission * attempt. Not after a silent `checkValidity()` alone. * @cssstate user-invalid - `invalid` after that same interaction. A pristine empty query is * invalid but deliberately does not match this, so a consumer's `:state(user-invalid)` styling * cannot paint the form red before the user has typed anything. A form reset makes it pristine * again. * @status stable * @since 4.1.0 */ export declare class LyraGraphQueryBuilder extends LyraElement{static formAssociated:boolean;static styles:import("lit").CSSResultGroup[];protected static readonly immutableEventDetails:readonly string[];static properties:{customError:{attribute:string;reflect:boolean;noAccessor:boolean;};name:{reflect:boolean;noAccessor:boolean;};value:{attribute:boolean;noAccessor:boolean;};disabled:{type:BooleanConstructor;reflect:boolean;noAccessor:boolean;};}; /** Clone-owned, bounded pickable relationship types offered by the "add" picker. */ private _relationshipTypeOptions;get relationshipTypeOptions():readonly GraphQueryTypeOption[];set relationshipTypeOptions(value:readonly GraphQueryTypeOption[]); /** Clone-owned, bounded pickable node types offered by the node-type "add" picker. */ private _nodeTypeOptions;get nodeTypeOptions():readonly GraphQueryTypeOption[];set nodeTypeOptions(value:readonly GraphQueryTypeOption[]); /** Clone-owned, bounded host-persisted saved queries. Controlled -- this component never mutates * this array itself; accepted `lr-query-save`/`lr-query-delete` notifications tell the host when * to act. Applying an accepted deletion from the focused row restores focus to the nearest * survivor or save input. */ private _savedQueries;get savedQueries():readonly GraphQuerySavedItem[];set savedQueries(value:readonly GraphQuerySavedItem[]); /** Upper bound (inclusive) offered by the minimum/maximum hop selects. Sanitized to a finite * integer in `[1, 20]`, falling back to `6`. */ hopLimit:number; /** Accessible name for the whole component; falls back to the localized `graphQueryBuilderLabel`. * A host-level `aria-label` attribute wins over both this property and the localized default -- * see the class doc's "Accessible name" note. */ label:string; /** Supporting text rendered below the outer label. */ hint:string; /** Caller-supplied outer error text. Field-level validation remains on the affected controls. */ errorText:string;private _errors;private touchedFields;private saveName;private hasHintSlot;private hasErrorSlot;private hintSlotEl?;private errorSlotEl?;private readonly labelId;private readonly hintId;private readonly errorId;private internals;private validityController; /** Consumer-supplied validation message reflected through `custom-error`. */ customError:string|null;private _fieldsetDisabled;private _name;private _value;private defaultValue;private defaultValueCaptured;private _disabled;private hasInteracted;private lastValidityKey;private pendingRemovalFocus?;private removalFocusGeneration; /** Projects a host `aria-describedby` onto the internal `role="group"` owner -- * IDREFs are scoped per shadow root, so the host's own attribute cannot reach across the * boundary on its own. Mirrors ``'s `externalDescriptionLease`. */ private externalDescriptionLease?;constructor();connectedCallback():void;disconnectedCallback():void;private syncExternalDescription;private releaseExternalDescription;get form():HTMLFormElement|null;set form(owner:FormOwnerValue);getForm():HTMLFormElement|null;get labels():NodeList;get validity():ValidityState;get validationMessage():string;get willValidate():boolean; /** The complete controlled query model, detached and deeply frozen with at most 500 relationship * and node type entries. Reassign a new model after changes. Its normalized value at the first * update is the form reset default; later property writes and user edits change only the live * value. */ get value():GraphQuery;set value(next:GraphQuery);get name():string;set name(next:string);get disabled():boolean;set disabled(next:boolean); /** Effective disabled state: this element's own `disabled` OR an ancestor * `
`'s inherited state. */ get effectiveDisabled():boolean; /** The current effective validation errors. Intrinsic errors are keyed by their field part; * a caller-supplied custom validity message is keyed by the whole-control `base` part. */ get errors():Readonly>;private publicValidityErrors;private publishValiditySnapshot;private computeValidation;private syncFormState; /** * Shared with every other form control in the library: own `disabled` and a `
` * ancestor both bar constraint validation, so a barred builder reports no failure and publishes * neither `:state(invalid)` nor `:state(user-invalid)` — see `internal/custom-states.ts`. */ private get barredFromValidation(); /** * Republishes the six `:state()` validity hooks — see `internal/custom-states.ts`. Called from * `syncFormState()` (so every validity recomputation carries them) and from `markTouched()`, the * one interaction that changes the answer without touching validity. * * `required` is unconditional: this control has no `required` property to key off because its one * constraint never lifts — `computeValidation()` always raises `valueMissing` for an empty * `startId`, since a path query with no anchor is not runnable. */ private syncValidityCustomStates;private markInteracted; /** Resynchronizes validity without revealing inline errors. */ checkValidity():boolean; /** Reveals every current field error and returns overall validity -- the hook Run calls before * acting, mirroring a native ``'s `reportValidity()`. */ reportValidity():boolean; /** * Sets or clears a consumer-supplied validation error — the standard channel for a server-side * rejection ("no graph is loaded for that tenant") that neither of this control's own two * constraints can express. A non-empty `message` raises `customError` and becomes * `validationMessage`, so the builder fails `checkValidity()`, blocks submission, and matches * `:state(invalid)`; `''` clears it. * * Clearing restores the control's own computed validity rather than forcing it valid: a query * with no `startId` stays `valueMissing`. The custom error also survives every intrinsic * recomputation in between (each field edit re-runs `syncFormState()`) and a `form.reset()` — * matching a native control, where only another `setCustomValidity('')` clears it. * * The message is caller-supplied content, so it is used verbatim and never localized here. It is * whole-control state and lands in `errors.base`, keyed to the complete control's `base` part. */ setCustomValidity(message:string):void;formResetCallback():void;private captureDefaultValue;formStateRestoreCallback(state:string|File|FormData|null,_mode?:'restore'|'autocomplete'):void;formDisabledCallback(disabled:boolean):void;private get liveDisabled();private focusFirstControl; /** Moves focus to the first rendered field while the aggregate control is enabled. */ focus(options?:FocusOptions):void; /** Blurs whichever nested editing owner currently holds focus. */ blur():void; /** Forwards host clicks to the first rendered control so callers can interact with this wrapper * as if it exposed a single root control. */ click():void;private setValue;private addRelationshipType;private removeRelationshipType;private addNodeType;private removeNodeType;private captureChipRemovalFocus;private markTouched;private runQuery;private saveQuery;private loadQuery;private deleteQuery;protected willUpdate(changed:PropertyValues):void;protected updated(changed:PropertyValues):void;private hopOptions; /** * Also called once from `firstUpdated()` (see `collectInitialSlotAssignment`) to cover an * environment, or a real-browser timing race, where a slot's initial assignment never fires * `slotchange`. Idempotent: re-reading the same still-assigned nodes just re-derives the same * boolean, so running once from `firstUpdated()` and again from a real initial `slotchange` (every * real-browser connect) produces no duplicate side effect. */ private onChromeSlotChange;private collectChromeSlotAssignment;protected firstUpdated(changed:PropertyValues):void;private labelForType;private containSelectEvent;private renderTypeFilter;render():TemplateResult;}declare global{interface HTMLElementTagNameMap{'lr-graph-query-builder':LyraGraphQueryBuilder;}}