import{type PropertyValues,type TemplateResult}from'lit';import{LyraElement}from'../../../internal/lyra-element.js';import type{LyraConversationItem}from'../conversation-item/conversation-item.class.js';import{type LyraSize}from'../../../internal/variants.js';import{type LyraTimestamp}from'../timestamp.js';export interface LyraChatThread{id:string; /** Required display/search text. Runtime records without a string title are omitted. */ title:string;excerpt?:string;timestamp?:LyraTimestamp;pinned?:boolean;archived?:boolean;}export type ThreadRowAction='pin'|'archive'|'delete';export type ThreadListGrouping='date'|'custom'|'none'; /** Payload shared by the `lr-group-toggle-request`/`lr-group-toggle` pair. */ export interface ThreadGroupToggleDetail{groupId:string;collapsed:boolean;}export interface LyraThreadListEventMap{'lr-select':CustomEvent<{conversationId:string;}>;'lr-thread-pin':CustomEvent<{conversationId:string;pinned:boolean;}>;'lr-thread-archive':CustomEvent<{conversationId:string;archived:boolean;}>;'lr-thread-delete':CustomEvent<{conversationId:string;}>;'lr-thread-rename':CustomEvent<{conversationId:string;label:string;}>;'lr-filter-change':CustomEvent<{text:string;matchCount:number;}>;'lr-query-change':CustomEvent<{text:string;}>;'lr-group-toggle-request':CustomEvent;'lr-group-toggle':CustomEvent; /** The built-in `[part='retry-button']` was activated, only rendered while `error` is set. * Cancelable: the default action clears `error`; `preventDefault()` leaves it set instead. */ 'lr-retry':CustomEvent;blur:CustomEvent;focus:CustomEvent;}export type ThreadBucketKey='pinned'|'today'|'yesterday'|'previous7'|'previous30'|`month:${string}`|'archived';export interface ThreadGroupContext{id:string;threads:readonly LyraChatThread[];bucket?:ThreadBucketKey;date?:Date;} /** * `` — the conversation sidebar: a grouped, searchable list of chat sessions with * pin/archive/delete/rename affordances. *Data mode* (non-empty `threads`, or empty `threads` with * nothing slotted) renders every row as a `` inside an internal * `` — virtualized by construction, scroll position and per-row state survive a * `threads` replacement; zero rows renders the built-in empty state. *Slotted mode* (empty `threads` * *and* real slotted content) renders host-supplied ``s from the default slot * as-is: no grouping, virtualization, or row actions in that mode — those are data-mode-only by design * (shadow DOM cannot inject group headers between slotted children). * * No thread CRUD or persistence: every mutation (`lr-thread-pin`/`-archive`/`-delete`/`-rename`) is * a controlled event carrying the *requested* new state — the host mutates `threads`. * Data-mode thread `id` values must be nonempty, nonblank, and unique. Untyped invalid rows and * later duplicates are omitted deterministically, so focus, virtualization, actions, and emitted * `conversationId` values all resolve to the first valid occurrence. * Arrow/Home/End navigation skips unavailable rows, including a row placed below an `inert` * ancestor by `wrapRow`. Arrow navigation continues through the complete item model at a virtual * window edge; Home/End always resolve the first/last complete-model thread even from a middle * window, mounting candidates until an available row can receive focus. * * Data mode: a host needing content with no home in `lr-conversation-item`'s own * `label`/`excerpt`/`meta`/`actions` surface sets `wrapRow` to wrap the already-built row. For * common row composition, `renderStart`, `renderExcerpt`, `renderMeta`, and `renderRowContent` * provide focused virtualized render hooks -- `renderExcerpt` renders into the row item's own * `excerpt` slot (winning over the plain-string `excerpt` property) for rich per-row content such * as a highlighted search snippet. A host needing a fully custom * `actions` surface itself — beyond `rowActions`'s closed `pin | archive | delete` set, e.g. a * `` + `` with Rename/Delete — sets `renderActions` instead; its content is appended after any * built-in `rowActions` output in the same slot, and `wrapRow` continues to compose around the result. * * Public collection properties take bounded, detached readonly sequences. Thread display fields * are projected from own data descriptors once per assignment; callbacks retain the caller's * exact source thread identity. Create a new collection and reassign it after changes; mutating * the assigned array does not update the view. * * A separate `error` state reports a failed load: while `error` is set, the built-in `` * failed-load state (the same `error`-prefixed exported parts and `[part='retry-button']` as * ``) replaces the virtual list/empty state, behind its own `error` slot. `error` beats * the built-in empty state, matching ``'s own precedence. * * @customElement lr-thread-list * @slot - Slotted mode only: host-supplied `lr-conversation-item`s, rendered in order. Each * top-level assigned element that doesn't already carry an explicit `role` is given * `role="listitem"`, since `[part="list"]` is `role="list"` in this mode and `lr-conversation-item` * deliberately doesn't self-apply that role (see its own class doc). * @slot empty - Replaces the built-in empty state. * @slot error - Replaces the built-in failed-load state, including its retry button, while `error` * is set. * @event lr-select - `detail: { conversationId }` -- a row was activated (data mode only). * @event lr-thread-pin - `detail: { conversationId, pinned }` -- the requested new state. * @event lr-thread-archive - `detail: { conversationId, archived }` -- the requested new state. * @event lr-thread-delete - `detail: { conversationId }` -- no built-in confirmation. * @event lr-thread-rename - `detail: { conversationId, label }`, re-emitted from the row's * correlated `lr-rename` request (data mode only). * @event lr-filter-change - `detail: { text, matchCount }` -- data-mode query plus owned results. * @event lr-query-change - `detail: { text }` -- slotted-mode query request; the host owns results. * @event lr-group-toggle-request - `detail: { groupId, collapsed }` -- cancelable proposal before a * custom/date group's collapse state changes. Calling `preventDefault()` skips the built-in * `collapsedGroupIds` write below and suppresses the following `lr-group-toggle`, leaving the * group's collapse state fully controlled -- the host must then reassign `collapsedGroupIds` * itself, mirroring ``'s and ``'s own * `lr-toggle-request`/`lr-toggle` pairs. * @event lr-group-toggle - `detail: { groupId, collapsed }` -- a custom/date group's collapse-state * change was accepted and, unless `lr-group-toggle-request` was prevented, already applied to * `collapsedGroupIds`. A host that already listens here and reassigns `collapsedGroupIds` itself * keeps working unchanged: this component's own write, when it happens, always precedes that * listener in the same synchronous event dispatch, so the host's own assignment simply wins last. * @event blur - `searchable`: re-dispatched from the internal search ``'s own `blur` -- * bubbling and composed (unlike the native event, which is neither), so a listener above the * shadow boundary can observe it. * @event focus - `searchable`: re-dispatched from the internal search ``'s own `focus`, * for the same reason as `blur`. * @event lr-retry - The built-in `[part='retry-button']` was activated, only rendered while * `error` is set. Cancelable: the default action clears `error`; `preventDefault()` leaves it * set instead. * @csspart base - The root. * @csspart search - The search field wrapper. * @csspart search-input - The ``. * @csspart clear-button - Clears the search field. Rendered only while it has a value. * @csspart list - The list region. * @csspart empty - The empty/no-matches state. * @csspart error - The built-in `` host rendered while `error` is set. * @csspart error-base - Exported from the built-in error ``'s own `base` part. * @csspart error-icon - Exported from the built-in error ``'s `icon` part. * @csspart error-heading - Exported from the built-in error ``'s `heading` part. * @csspart error-description - Exported from the built-in error ``'s `description` part. * @csspart error-actions - Exported from the built-in error ``'s `actions` part. * @csspart retry-button - The built-in retry control rendered into the error state's `actions`. * @csspart viewport - The real scroll container, exported from the internal `lr-virtual-list`. It * fills this component's height with no consumer CSS (and falls back to `lr-virtual-list`'s own * 24rem `--lr-virtual-list-height` default when the container has no resolvable height). * @csspart row-action - A built-in pin/archive/delete icon button (data mode, when `rowActions` includes it). * @csspart pin-glyph - The small pin indicator shown in a pinned row's `meta` slot (data mode). * @csspart group-header - A date/custom group header in data mode. * @csspart group-sticky - `sticky-groups` only: the pinned copy of the current group's header, * exported from the internal `lr-virtual-list`'s sticky layer. It repeats the `group-header`, * `group-label`, and `group-icon` visuals but is `aria-hidden`, inert, and pointer-transparent; * the real row remains the sole `group-toggle`. Style this part for the pinned band itself, e.g. * a shadow or a border under the band. * @csspart group-toggle - The controlled group expand/collapse button. * @csspart group-label - The group label inside `group-toggle`. * @csspart group-adornment - Optional rich `renderGroupAdornment` output beside the toggle. * @csspart group-icon - The decorative expand/collapse glyph. * @csspart row - Exported from the internal `lr-virtual-list`'s `row` part (data mode). * @csspart row-wrapper - The wrapper around `wrapRow` output (data mode, only when `wrapRow` is * set). Row-only: group headers are never passed through `wrapRow`, so they never carry it. * @csspart row-start - The wrapper around `renderStart` output. * @csspart row-excerpt - The wrapper around `renderExcerpt` output, slotted into the row item's own * `excerpt` slot. * @csspart row-content - The wrapper around `renderRowContent` output. * @csspart row-meta - A wrapper around built-in or `renderMeta` metadata. * @csspart row-actions - The wrapper around built-in and `renderActions` output. * @csspart row-item-base - Data mode: the row ``'s own `base` part — the box * whose padding sets row height. `row-item-*` parts are the item's *internals*; the `row-*` parts * above wrap this component's own callback output and are a different surface. Styling row * density here replaces the older `::part(row) { --lr-theme-*: … }` workaround, which retheme'd * the whole row subtree (`renderActions` popups included). * @csspart row-item-active-indicator - Data mode: the row item's decorative active indicator, * exported from `lr-conversation-item`. * @csspart row-item-select-button - Data mode: the row item's selectable button-like region. * @csspart row-item-start - Data mode: the row item's `start` wrapper. * @csspart row-item-content - Data mode: the row item's label/excerpt content column. * @csspart row-item-label - Data mode: the row item's visible label. * @csspart row-item-label-input - Data mode: the row item's in-place rename ``. * @csspart row-item-rename-button - Data mode: the row item's pencil/rename affordance. * @csspart row-item-excerpt - Data mode: the row item's excerpt line. * @csspart row-item-meta - Data mode: the row item's `meta` wrapper. * @csspart row-item-timestamp - Data mode: the row item's `