import type{LyraEventDetailSnapshot}from'../../../internal/lyra-element.js';import type{LyraDateRangePreset}from'../../forms/date-picker/date-picker.class.js';import type{LyraInputType}from'../../forms/input/input.class.js';import type{LyraSize}from'../../../internal/variants.js';import{type TemplateResult,type PropertyValues}from'lit';import{LyraElement}from'../../../internal/lyra-element.js'; /** Which existing Lyra input family renders a given filter -- this component composes these, * it never invents a new filter-input type of its own. `'date'` and `'date-range'` both map * to `` (single vs. `mode="range"`); `'select'`/`'combobox'` map to their * same-named counterparts, with `combobox`'s own `multiple` opting into a multi-value filter; * `'text'` -- an open-ended free-text query rather than a closed choice set -- maps to * ``, composed exactly like the rest (its own label/hint/error chrome, its own * `required`), with this component adding only the optional `debounce` every free-text filter * otherwise hand-rolls at the call site. `'checkbox-menu'` maps to `` plus one * `` per option -- the library's own checkbox menu, a * toolbar-button shape for a small fixed set of independently togglable categories, with the * same `string[]` value a `'combobox'` with `multiple` carries. `'custom'` delegates rendering * and event-to-value conversion to the definition's `custom` adapter, so an existing Lyra * control can participate without this component growing a branch for every control family. * `'chip'` is the one type that maps to no control at all: its value is owned by a widget * elsewhere on the page, and this component renders only its active-filter chip. */ export type LyraFilterBarControlType='select'|'combobox'|'checkbox-menu'|'date'|'date-range'|'text'|'chip'|'custom'; /** One closed-set choice for a `'select'`/`'combobox'` filter. */ export interface LyraFilterBarOption{readonly value:string;readonly label:string; /** Optional decorative leading visual rendered into the ``'s `start` slot — a status * dot, a type glyph, a flag. Deliberately general Lit content rather than an icon-name string, * matching `LyraSegmentedItem`/`LyraPaletteItem`'s own `icon` fields. It is rendered inert and * `aria-hidden`, so it never contributes to the option's accessible name. */ readonly icon?:unknown; /** Extra text this option also matches on, forwarded verbatim to ``'s own * `search-text`, so a `'combobox'` filter can match a long canonical key ("SEV-1 production * outage") while the row keeps displaying the short `label` ("Urgent"). **`'combobox'` only.** * The attribute is written on every choice type's ``, but only `` * consults it: ``'s listbox type-ahead matches the option's `label` alone, so * declaring `searchText` on a `'select'` filter's options changes nothing there, and a * `'checkbox-menu'` has no text entry to match against at all. Omitted leaves the control's * default (match on the label alone). */ readonly searchText?:string; /** * Marks this option non-actionable: forwarded to ``'s own `disabled` for a `'select'` * or `'combobox'` filter, and to the composed ``'s own `disabled` for a * `'checkbox-menu'` filter. The composed control already renders it as a genuinely disabled row * (no tab stop / roving stop, no hover or press affordance, `aria-disabled`) and already steps * roving/arrow-key navigation past it -- this field only forwards a value that control already * knows how to honour. Omitted or `false` renders the option exactly as before this field * existed. */ readonly disabled?:boolean;} /** One filter's current value. Built-in controls use strings/string arrays; an untyped boolean * `false` at that boundary is canonical empty while `true` remains set. Custom controls may use * either boolean meaning through their adapter (for example, an `lr-checkbox` filter). */ export type LyraFilterBarFieldValue=string|readonly string[]|boolean|undefined; /** Value/label bridge for a custom filter control. The renderer wires one of the context's event * handlers to the control's committed-change event; the adapter turns that event into the plain * value stored by `lr-filter-bar`. */ export interface LyraFilterBarCustomControlAdapter{ /** Reads the new filter value from the custom control's event. `event.currentTarget` is the * rendered control when the handler is attached directly to it. */ readonly valueFromEvent:(event:Event)=>LyraFilterBarFieldValue; /** Canonical value that means this custom filter is cleared. Cleared values are omitted from * the sparse bar value. */ readonly clearValue:LyraFilterBarFieldValue; /** Optional domain-specific empty predicate. When omitted, `Object.is(value, clearValue)` is * used (with shallow string-array equality for array clear values). */ readonly isEmpty?:(value:LyraFilterBarFieldValue)=>boolean; /** Formats the stored value for the active-filter chip. When omitted, strings and arrays use * the same list formatting as built-in choice filters and booleans render as `true`/`false`. * `locale` is `effectiveLocale`, the same value every built-in filter type's own chip formatting * (`getListFormat`/`getDateTimeFormat`) already receives -- an existing single-argument * `formatValue` implementation keeps working unchanged, since JS simply ignores a second * argument it never declared. */ readonly formatValue?:(value:LyraFilterBarFieldValue,locale:string)=>string;} /** Context supplied to a custom filter renderer. The renderer owns the custom control's markup * and should bind `value`, `disabled`, `required`, and `errorText` as appropriate for that * control, then attach `onValueChange` (or the more specific `onInput`/`onChange`) to its * committed-value event and `onFocusout` to its blur/focusout event. */ export interface LyraFilterBarCustomControlContext{ /** The custom definition's stable business identity. */ readonly filterId:string;readonly label:string;readonly definition:LyraFilterBarCustomDefinition; /** While `definition.debounce` has a commit pending, this is that pending value rather than the * last-committed one -- exactly like `'combobox'`'s own debounce -- so a renderer that binds * this as a fully controlled `.value=` never reverts mid-delay. Otherwise the last-committed * value, same as always. */ readonly value:LyraFilterBarFieldValue;readonly disabled:boolean;readonly required:boolean;readonly errorText:string; /** Aborted when this exact schema is replaced, removed, disconnected, or superseded after * reconnect, so async custom renderers can release their work. */ readonly signal:AbortSignal; /** Monotonic schema identity for diagnostics and cache keys. */ readonly generation:number; /** Directly commits a value, useful for a custom control whose event has no DOM event payload. */ readonly setValue:(value:LyraFilterBarFieldValue)=>void; /** Reads the adapter value and commits it -- immediately, or (with `definition.debounce` set) via * that same delayed-commit path; stopPropagation is handled by the filter bar. */ readonly onValueChange:(event:Event)=>void; /** Aliases for consumers whose custom control uses native-style input/change naming. */ readonly onInput:(event:Event)=>void;readonly onChange:(event:Event)=>void; /** Marks the custom filter touched so required validation becomes visible, flushing a pending * `definition.debounce` commit first so an unflushed edit never flashes a stale required error. */ readonly onFocusout:()=>void;} /** Renderer and adapter for a `type: "custom"` filter definition. The returned control is placed * inside the filter bar's `filter-control` part and is re-rendered with the current value. */ export interface LyraFilterBarCustomControl{readonly render:(context:LyraFilterBarCustomControlContext)=>TemplateResult;readonly adapter:LyraFilterBarCustomControlAdapter;} /** Whether a filter's `label` renders as the composed control's own visible label -- `'visible'`, * the default and the behaviour every definition had before this option existed -- is routed to * that control's accessible name instead (`'hidden'`), for a compact toolbar row, or is * `'auto'`: rendered as the visible label while the bar's own allocation is wide enough for it, * and visually clipped (never removed, so the name is unchanged) once it is not. */ export type LyraFilterBarLabelVisibility='visible'|'hidden'|'auto'; /** Which currently-active filters `render()`'s chip row shows -- see `LyraFilterBar.activeFiltersDisplay`. */ export type LyraFilterBarActiveFiltersDisplay='all'|'changed'|'hidden';interface LyraFilterBarDefinitionBase{ /** Stable, unique business identity and the key used in `LyraFilterBarValue`. */ readonly filterId:string; /** Visible label, forwarded to the composed control's own `label` prop (so it renders through * that control's own label/hint/error chrome) -- caller-supplied content, not routed through * `this.localize()` by this component (the same "data, not UI copy" carve-out a table's own * column headers get). */ readonly label:string;readonly placeholder?:string;readonly required?:boolean;readonly defaultValue?:string|readonly string[]|boolean;} /** The fields every built-in (non-`'custom'`) filter type forwards to whichever Lyra control it * composes. They live here rather than on each type so one filter row can be declared compact, * adorned and labelled the same way regardless of which control renders it. A `'custom'` * definition deliberately does NOT extend this: its renderer owns the control's markup outright, * so a field this component could not forward anywhere would be inert public API. */ interface LyraFilterBarComposedDefinitionBase extends LyraFilterBarDefinitionBase{ /** Forwarded to the composed control's own `size`, the library's one shared control ladder. * Defaults to `'m'`, matching every one of those controls' own default. */ readonly size?:LyraSize; /** Optional decorative leading visual rendered into the composed control's own `start` slot, * exactly like `LyraFilterBarOption.icon`: inert and `aria-hidden`, so it never contributes to * the field's accessible name. */ readonly icon?:unknown; /** Whether `label` renders as the composed control's own visible label (`'visible'`, the * default) or is routed to its accessible name instead (`'hidden'`) -- which also supplies the * label as the control's `placeholder` when the definition declares none, so the field still * reads as itself with no stacked label above it. The label never simply disappears: routing it * is the point, and a filter whose label were dropped would leave the control unnamed. * * `'auto'` is the width-dependent middle: the label renders exactly as `'visible'` does -- * same stacked label element, same accessible name computed from it, no `aria-label` and no * placeholder fallback -- and is *visually clipped* by this component's own stylesheet once the * bar's own allocation drops below `30rem` (a container query on the host, so it reads the bar's * allocated width and not the viewport's). Clipped, never removed: the name comes from the same * node at every width, which is exactly what visually hiding `::part(filter-control-label)` from * a consumer stylesheet could not achieve. The threshold is fixed rather than themeable -- a * container query's prelude cannot read a custom property, so a `--lr-*` hook for it would parse * and silently never apply. */ readonly labelVisibility?:LyraFilterBarLabelVisibility;} /** The composed fields whose control also ships a built-in clear action. `'checkbox-menu'` is * deliberately absent: its composed `` has no clear affordance of its own, and the * active-filter chip's own remove action already clears it. */ interface LyraFilterBarClearableDefinitionBase extends LyraFilterBarComposedDefinitionBase{ /** Forwarded to the composed control's own clear action (`clearable` on ``/ * ``/``, the same option under its `with-clear` spelling on * ``). Defaults to `false`, matching those controls' own default. */ readonly clearable?:boolean;}export interface LyraFilterBarSelectDefinition extends LyraFilterBarClearableDefinitionBase{readonly type:'select';readonly options:readonly LyraFilterBarOption[];} /** A `'checkbox-menu'` filter: `` plus one `` * (`role="menuitemcheckbox"`) per option, behind a single toolbar trigger button. Its value is a * `string[]` exactly like a `'combobox'` with `multiple`, so the two are interchangeable in the * bar's value record, chips, reset path and events -- the choice between them is an interaction * one: a searchable list of many values versus a small fixed set toggled in place. Unlike every * other built-in type it renders no stacked label above its control; the trigger button carries * the label as its own text, and `labelVisibility: 'hidden'` makes that text visually hidden * (never removed) so the button keeps its accessible name. */ export interface LyraFilterBarCheckboxMenuDefinition extends LyraFilterBarComposedDefinitionBase{readonly type:'checkbox-menu';readonly options:readonly LyraFilterBarOption[];}export interface LyraFilterBarComboboxDefinition extends LyraFilterBarClearableDefinitionBase{readonly type:'combobox';readonly options:readonly LyraFilterBarOption[]; /** A `multiple` combobox filter collapses past the composed ``'s own * `max-options-visible` (default `3`, not forwarded by this component) into a localized "+N" * overflow indicator -- the same substance as ``'s own `multiple`-mode overflow chip. * The one remaining gap: ``'s overflow chip carries a second, distinguishing * `tag-overflow` part so a consumer can style just that chip; ``'s carries only the * plain `tag` part, so there is no equivalent token for this component to forward as * `filter-control-tag-overflow`. That is ``'s own surface to grow, not something * `exportparts` can manufacture for a part its composed child never renders. */ readonly multiple?:boolean; /** `'combobox'` only -- how long (ms) to wait after the last selection change (a pick, a * multi-select toggle, an `allowCustomValue`/`allowCreate` commit, or the clear action) before * committing it to `value` and emitting a single `lr-input`, coalescing a burst of rapid picks * into one commit the same way `'text'`'s own `debounce` coalesces keystrokes. Omitted, `0`, or * a non-finite value means no debounce at all: every change commits immediately. Unlike * `'text'`, the composed ``'s `.value=` binding stays fully controlled throughout: * while a commit is pending, it renders that pending selection rather than the last-committed * `value`, so the control's own display never reverts mid-delay. A pending debounce is flushed * by the control's own blur/focusout and cancelled outright by `reset()`, a chip removal, and * disconnection -- identical to `'text'`. */ readonly debounce?:number; /** Forwarded to the composed ``'s own `empty-text`: what its listbox shows when a * query matches none of the declared options ("No matching tags"). `'combobox'` only. Caller * copy, so -- like `label` -- it is not routed through `this.localize()`; omitted leaves that * control's own localized default in place. */ readonly emptyText?:string;}export interface LyraFilterBarTextDefinition extends LyraFilterBarClearableDefinitionBase{readonly type:'text'; /** `'text'` only -- how long (ms) to wait after the last keystroke before committing the typed * value to `value` and emitting a single `lr-input`, so a server-side query runs once per pause * instead of once per character. Omitted, `0`, or a non-finite value means no debounce at all: * every keystroke commits immediately. A pending debounce is always flushed by the field's own * `change`/blur (so a blur never loses the last keystroke) and cancelled outright by * `reset()`, a chip removal, and disconnection. Ignored for every other `type`, whose commits * are discrete choices with nothing to debounce. */ readonly debounce?:number; /** Forwarded verbatim to the composed ``'s own `type`, so a `'text'` filter can render * as `search`/`email`/`tel`/`url`/etc. instead of the default `text`. `'text'` only. */ readonly inputType?:LyraInputType;}interface LyraFilterBarDateDefinitionBase extends LyraFilterBarClearableDefinitionBase{ /** ISO `YYYY-MM-DD` lower bound, forwarded to ``'s own `min`. `'date'`/`'date-range'` only. */ readonly min?:string; /** ISO `YYYY-MM-DD` upper bound, forwarded to ``'s own `max`. `'date'`/`'date-range'` only. */ readonly max?:string;}export interface LyraFilterBarDateDefinition extends LyraFilterBarDateDefinitionBase{readonly type:'date';}export interface LyraFilterBarDateRangeDefinition extends LyraFilterBarDateDefinitionBase{readonly type:'date-range'; /** Quick-range options ("Last 7 days", "This month", "All time") forwarded verbatim to the * composed ``'s own `presets`, exactly like `min`/`max` -- this is the dashboard * filter shape that row was built for, and `type: 'custom'` would mean hand-rendering the same * control plus a full adapter just to set one property, forfeiting the built-in date-range chip * localization on the way. * * `'date-range'` only, deliberately not on the shared date base: a preset names two dates, so * `` ignores the list outside range mode, and declaring it on `'date'` would * type-check a field that is guaranteed inert. Which preset a commit came from arrives on that * edit's own `lr-input` as `appliedPreset`. */ readonly presets?:readonly LyraDateRangePreset[];}export interface LyraFilterBarCustomDefinition extends LyraFilterBarDefinitionBase{readonly type:'custom';readonly custom:LyraFilterBarCustomControl; /** How long (ms) to wait after the custom control's own committed-value event (whatever the * adapter's `valueFromEvent` reads via `context.onValueChange`/`onInput`/`onChange`) before * committing it to `value` and emitting a single `lr-input` -- identical to `'text'`'s * per-keystroke debounce and `'combobox'`'s per-selection-change debounce, and sharing the same * per-`filterId` debounce-controller map, so it needs no separate wiring. Omitted, `0`, or a * non-finite value means no debounce at all: every commit lands immediately, exactly as before * this field existed. While a commit is pending, `context.value` renders that pending value * rather than the last-committed `value` -- exactly like `'combobox'` -- so a custom control * bound to it as a fully controlled `.value=` never reverts mid-delay. A pending debounce is * flushed by `context.onFocusout` and cancelled outright by `reset()`, a chip removal, and * disconnection, identical to `'text'`/`'combobox'`. This closes the gap `'text'`'s own * debounce left: before this field existed, a custom free-text filter had to hand-roll the same * timer plus its flush/cancel lifecycle itself to get the same behaviour. */ readonly debounce?:number;} /** A control-less filter whose value is owned by a widget elsewhere on the page -- a calendar * heatmap cell, a map selection, a chart brush. `` renders NO control for it and it * occupies NO toolbar cell, but it is a filter in every other sense this component knows: it lives * in `value` under its own `filterId`, rides every `lr-input`/`lr-reset` detail, counts toward * `hasActiveFilters` (so it enables the reset button) and `invalidFilterIds`, renders a removable * active-filter chip subject to `activeFiltersDisplay`, and is cleared by a chip removal and by * `reset()` alongside every other filter. * * It extends the shared definition base rather than the composed one for the same reason * `'custom'` does: `size`/`icon`/`labelVisibility`/`clearable` have no control to be forwarded to, * so declaring them would be inert public API. The inherited `placeholder` is likewise inert here * (there is no field to place it in), exactly as it already is for `'custom'`. The inherited * `required` IS honoured, but only in bookkeeping: a required-but-empty chip filter appears in * `invalidFilterIds` and fails `checkValidity()`, while rendering no inline error -- this component * renders no element for that filter on which one could appear, so the widget that owns the value * owns its error affordance too. The inherited `defaultValue` is * restored by `reset()` and compared by `activeFiltersDisplay: 'changed'` like any other type's. */ export interface LyraFilterBarChipDefinition extends LyraFilterBarDefinitionBase{readonly type:'chip'; /** The chip's text for the current value. `locale` is `effectiveLocale` -- the same value every * built-in type's own chip formatting (`getListFormat`/`getDateTimeFormat`) and a custom * adapter's `formatValue` already receive -- because such a value is normally a formatted string * (a localized date) rather than a label looked up in an options list. Caller-supplied copy, so * (like `label`) this component does not route the result through `this.localize()`; passing the * locale is what lets the caller do it. Omitted falls back to the same ladder a custom adapter's * omitted `formatValue` uses: a string array formats as a localized conjunction list, any other * value renders `String(value)`, and `undefined` renders `''`. */ readonly formatValue?:(value:LyraFilterBarFieldValue,locale:string)=>string; /** The value written when this filter's chip is removed (or `clearFilter()` runs). Defaults to * `''`, matching what every non-multi built-in type writes. Declare `[]` for a `string[]`-valued * chip filter. A domain sentinel (`'all'`) must be paired with `isEmpty`, or the bar will treat * the "cleared" value as still set and keep rendering a chip for it -- the identical pairing * `LyraFilterBarCustomControlAdapter.clearValue`/`isEmpty` documents. */ readonly clearValue?:LyraFilterBarFieldValue; /** Optional domain-specific empty predicate. Omitted, this filter uses the same built-in rule * every non-`'custom'` type uses: absent, `false`, `''` and `[]` are empty, everything else is * set. */ readonly isEmpty?:(value:LyraFilterBarFieldValue)=>boolean;} /** A host-declared filter. The discriminant makes choice options and custom adapters mandatory * exactly where runtime needs them, while excluding irrelevant fields from every other mode. */ export type LyraFilterBarFilterDefinition=LyraFilterBarSelectDefinition|LyraFilterBarComboboxDefinition|LyraFilterBarCheckboxMenuDefinition|LyraFilterBarTextDefinition|LyraFilterBarDateDefinition|LyraFilterBarDateRangeDefinition|LyraFilterBarChipDefinition|LyraFilterBarCustomDefinition; /** * The whole filter bar's current state: a plain, JSON-serializable object keyed by * `LyraFilterBarFilterDefinition.filterId`. This is the entire URL-querystring/app-state serialization * contract -- this component only reads and writes plain data through `value`, and never touches * `location`/`history`/storage itself; the host owns turning this object into (and back out of) * a querystring, matching every other Lyra "controlled" component's convention. */ export type LyraFilterBarValue=Readonly>; /** * The `value` field shape one filter definition implies, at the type level only -- the same * per-definition narrowing `LyraPickerValue` (`picker-value.ts`) does for * ``/``, applied to ``'s per-`filterId` value record * instead of a single control's own `value`. A `'checkbox-menu'` (always `string[]`, exactly like * a `multiple` `'combobox'`) and a `'combobox'` with `multiple: true` narrow to `readonly * string[]`; every other `'combobox'` and every `'select'`/`'text'`/`'date'`/`'date-range'` narrow * to `string`; a `'custom'` definition keeps the full unconstrained `LyraFilterBarFieldValue`, * since its adapter is free to use either boolean meaning (see `LyraFilterBarCustomControlAdapter`), * and so does a `'chip'` definition, whose value is owned by a widget this component never renders. */ export type LyraFilterBarDefinitionValue =D extends LyraFilterBarCheckboxMenuDefinition?readonly string[]:D extends LyraFilterBarComboboxDefinition?D extends{multiple:true;}?readonly string[]:string:D extends LyraFilterBarCustomDefinition?LyraFilterBarFieldValue:D extends LyraFilterBarChipDefinition?LyraFilterBarFieldValue:string; /** * `LyraFilterBarValue` narrowed to a keyed record whose per-`filterId` value type follows the * matching entry in `Defs` -- the filter-bar analogue of `LyraPickerValue`. * * `readonly LyraFilterBarFilterDefinition[] extends Defs` is true only for that unnarrowed * default (mirroring the `boolean extends Multiple` check `LyraPickerValue` uses), so an untyped * `` -- every shipped call site -- keeps exactly today's `LyraFilterBarValue` and * compiles unchanged. A literal `Defs` (typically declared with `as const satisfies readonly * LyraFilterBarFilterDefinition[]`) instead narrows each key to its own definition's value type. * This is deliberately types-only: the runtime shape (`LyraFilterBarFieldValue` per key) is * unchanged either way. * * ```ts * const FILTERS = [ * { filterId: 'status', label: 'Status', type: 'select', options: [...] }, * { filterId: 'tags', label: 'Tags', type: 'combobox', multiple: true, options: [...] }, * ] as const satisfies readonly LyraFilterBarFilterDefinition[]; * declare const bar: LyraFilterBar; * bar.value.status; // string | undefined * bar.value.tags; // readonly string[] | undefined * ``` */ export type LyraFilterBarValueFor =readonly LyraFilterBarFilterDefinition[]extends Defs?LyraFilterBarValue:Readonly<{[D in Defs[number]as D['filterId']]?:LyraFilterBarDefinitionValue;}>;export interface LyraFilterBarInputDetail{ /** The full current value of every filter, not just the one that changed. */ readonly value:LyraFilterBarValueFor; /** The filter that changed, or `undefined` when every filter changed at once (a `reset()`). */ readonly filterId?:string; /** For a `'date-range'` filter committed from its quick-range row: the `presets` entry that * produced this value, resolved from the composed ``'s own `appliedPreset`. * `undefined` for every other filter type, and for a range picked or typed by hand. * * A filter bar whose values round-trip through a query string has to persist WHICH preset is * active rather than the pair it froze to -- "Last 7 days" must still mean the last 7 days after * tomorrow's reload -- and that fact is not recoverable from `value`, which holds only the frozen * ISO range. It rides the event rather than `value` because it is metadata about one edit, not a * filter value: `value` stays the plain, JSON-serializable record it has always been. The entry * is the bar's own frozen snapshot of the definition, so it compares identical to * `filters[i].presets[j]`. */ readonly appliedPreset?:LyraDateRangePreset;}export interface LyraFilterBarValidityDetail{readonly valid:boolean; /** Filter ids currently failing their own `required` check. */ readonly invalidFilterIds:readonly string[];}export interface LyraFilterBarResetDetail{readonly value:LyraFilterBarValueFor;}export interface LyraFilterBarEventMap{'lr-input':CustomEvent>;'lr-validity-change':CustomEvent>;'lr-reset':CustomEvent>;} /** * Stable per-event aliases, so a host can name one event's type without restating the detail * schema (or re-deriving it from `LyraFilterBarEventMap`). Each narrows with the same `Defs` * parameter the component does: `LyraFilterBarInputEvent`'s `detail.value.status` * follows that `filterId`'s own definition. */ export type LyraFilterBarInputEvent =LyraFilterBarEventMap['lr-input'];export type LyraFilterBarResetEvent =LyraFilterBarEventMap['lr-reset']; /** * `` — a row of dashboard filters, each declared by the host (`filters`) rather * than invented by this component: every filter composes an existing Lyra input -- * ``/`` for closed choice sets, `` (single or `mode="range"`) * for dates, `` for a free-text query -- plus a `` of removable * ``s summarizing the currently-active filters (which filters that row admits is * `activeFiltersDisplay`'s own contract; removing a chip always clears that filter, regardless of * which chips the row is currently showing), an `` that resets every filter, and (while * `loading`) an `` status indicator. * * A `'text'` filter is the one control that is *not* a fully controlled `.value=` binding: a text * field re-rendered from `value` mid-typing would push a stale value back into the field and drop * the caret to the end, so the field owns its own value while the user types and an external * `value` write is synced back in only once no edit is in flight (see `syncTextControls()`). Its * optional per-filter `debounce` (ms) is the only behaviour this component adds on top of the * composed control itself -- flushed by that field's own `change`/blur, cancelled by `reset()`, a * chip removal, and `disconnectedCallback`, so a stale keystroke can never overwrite a reset or * fire after teardown. A `'combobox'` filter may declare the same `debounce`, coalescing a burst * of rapid picks into one delayed commit; unlike `'text'` its `.value=` binding stays fully * controlled, rendering the pending selection in place of the last-committed `value` for as long * as the commit is delayed. A `'custom'` definition may declare the same `debounce` too, applied to * whatever its adapter's `valueFromEvent` reads off `context.onValueChange`/`onInput`/`onChange`, * with identical flush-on-`context.onFocusout` and cancel-on-`reset()`/chip-removal/disconnect * semantics -- so a custom free-text filter no longer has to hand-roll that timer itself just to * match what `'text'` already does. Every built-in (non-`'custom'`) type also accepts optional * `size`/`icon`/`labelVisibility`, and every one whose composed control ships a clear action also * accepts `clearable` -- forwarded verbatim to that control's own same-named property (`icon` into * its `start` slot exactly like `LyraFilterBarOption.icon`; `clearable` reaching * `` under its `with-clear` spelling). `'text'` adds `inputType`, `'combobox'` adds * `emptyText`, and an option may carry `searchText` -- which only `` reads, since * ``'s type-ahead matches on the option label alone. `labelVisibility: 'hidden'` routes `label` to * the composed control's own `aria-label` and, with no declared `placeholder`, to its placeholder, * so a compact toolbar row still names every field. Every one of these is optional and defaults to * that composed control's own default, so an existing filter definition renders unchanged. * * A `'checkbox-menu'` filter is the one built-in type whose composed control is not a field: * `` plus one `` per option, behind a single * toolbar trigger that carries the label as its own text (no stacked label above it) and a menu * that stays open across toggles. Its value is a `string[]`, identical to a `'combobox'` with * `multiple`, so the two are interchangeable everywhere the bar's own bookkeeping is concerned -- * choose between them on interaction, not on data shape. Because its trigger is a button rather * than a field, it deliberately renders no required marker and sets no `aria-invalid`: the * library's shared `formControlRequiredMarker` has no selector that matches a button trigger's * label, and `` does not forward a host `aria-invalid` onto the element that owns the * button role, so writing one would be silently inert. A revealed `required` error still reaches * assistive technology, as a screen-reader-only run inside the trigger's accessible name. * * A `'chip'` filter is the one type that composes no control at all. Its value is owned by a widget * elsewhere on the page -- a calendar heatmap cell, a map selection, a chart brush -- so the bar * renders no field for it and it claims no toolbar cell (no `field` wrapper, and therefore no blank * column where an empty one's validation spacer would otherwise reserve a row of height). It is a * filter in every other sense: it lives in `value` under its own `filterId`, rides every * `lr-input`/`lr-reset` detail, counts toward `hasActiveFilters` (so it enables the reset button, * which is exactly the "clear all" action an all-chip bar needs) and `invalidFilterIds`, renders a * removable active-filter chip subject to `activeFiltersDisplay`, and is cleared by a chip removal * and by `reset()` alongside every other filter. Its chip text comes from an optional * `formatValue(value, locale)` receiving `effectiveLocale` -- the same locale every built-in type's * own chip formatting and a custom adapter's `formatValue` already receive; omitted, a string array * formats as a localized conjunction list and anything else renders `String(value)` verbatim, never * through the date branch that would reformat an ISO day or mangle a value containing a slash. * `clearValue` (default `''`) is what a chip removal writes; a domain sentinel must be paired with * `isEmpty`, exactly as a custom adapter's own `clearValue`/`isEmpty` are. Its inherited * `placeholder` is inert (there is no field to place it in), as it already is for `'custom'`, and * its inherited `required` is honoured in bookkeeping only: a required-but-empty chip filter joins * `invalidFilterIds`/`checkValidity()`/`lr-validity-change` but renders no inline error, since this * component renders no element of its own on which one could appear. * * Controlled, like every other Lyra data component: `value` is a plain, JSON-serializable object * (`LyraFilterBarValue`) the host reads/writes directly -- this component never touches * `location`/`history`/storage itself, so turning `value` into (and back out of) a URL * querystring or an app state store is entirely the host's own concern. Every edit -- picking an * option, committing a date, removing an active-filter chip, or clicking reset -- goes through * the same `setFilterValue()` path and emits a single `lr-input` carrying the *full* resulting * `value`, not just the changed filter's own value, mirroring ``'s identical * "always the whole object" event contract. A composed control's own `lr-input`/`lr-change` * aliases stay inside this wrapper; its native-style `input`/`change` events retain their normal * bubbling path. Date/date-range chip labels localize only * round-trip-valid ISO `YYYY-MM-DD` segments, including literal four-digit years `0000`-`0099`. * Impossible dates, malformed values, and a range with either invalid endpoint remain verbatim so * display never invents a normalized day. A `'date-range'` filter may also declare `presets`, * forwarded to its composed `` exactly like `min`/`max`; the entry that produced a * commit rides that edit's own `lr-input` as `appliedPreset`, so a bar whose values round-trip * through a query string can persist which range is active rather than the pair it froze to. * * Validation is scoped to each filter definition's own `required` flag: `invalidFilterIds`/ * `checkValidity()` are always live (plain getters over `filters`/`value`, not cached), and * `reportValidity()` additionally reveals every currently-invalid filter's inline error (rendered * by that filter's own composed control, via its `errorText`/`required` props -- this component * never renders a second, duplicate label/hint/error chrome of its own around an already-chromed * control) the same way a blur naturally would. `lr-validity-change` fires whenever the computed * `{ valid, invalidFilterIds }` actually changes. * * Deliberately not form-associated: a dashboard filter bar's state is not a submitted form field, * and every value it holds already round-trips through `value` directly -- see `disabled` below, * a plain property with no `
` cascade, for the same reason. * * The composed reset action stays on `lr-button`'s default `m` size tier, matching the default * select/combobox/input/date field height beside it instead of introducing a shorter action row. * The active-filter row and its composed chip group also zero every nested flex auto minimum, so * an unbroken localized value stays inside a narrow allocation and the chip's own label ellipsis * remains the overflow owner in both writing directions. * * @customElement lr-filter-bar * @event lr-input - A filter's value changed (including a chip removal or `reset()`). * `detail: { value, filterId, appliedPreset }` -- `value` is always the complete object; * `filterId` is the one filter that changed, or `undefined` for a `reset()`; `appliedPreset` is * the `'date-range'` quick-range entry that produced this commit, and `undefined` everywhere * else (another filter type, or a range picked/typed by hand). * @event lr-validity-change - The computed `{ valid, invalidFilterIds }` changed. * @event lr-reset - `reset()` ran (via the reset button or a direct call). `detail: { value }`. * @slot end - Extra host-supplied controls rendered inside `controls`, next to the reset button * (for example, a "Save search" or "Export" action) -- this component renders no default * content into it. * @csspart base - The root `role="group"` wrapper. * @csspart controls - The row holding every filter control, the `end` slot, the reset button, and * the loading status. * @csspart field - The wrapper around one filter's composed control and its validation spacer; * its flex-basis is `--lr-filter-bar-field-basis`. Also carries a second, per-filter token, * `field-` (for example `part="field field-status"`), so a consumer can target one * field's own wrapper -- `lr-filter-bar::part(field-status) { flex: 2 1 20rem; }` -- and set any * layout property, not just width, without affecting `::part(field)` rules that still match * every field. The `field-` token is omitted (the wrapper renders `part="field"` * alone) when `filterId` is not a plain CSS ident (ASCII letters/digits/`-`/`_`, starting with a * letter) -- `part` is a space-separated token list like `class`, so an id containing whitespace * would otherwise silently fabricate an unrelated second token (including, in the worst case, * one colliding with a real part name like `active-filters`). A `'chip'` filter renders no * `field` wrapper at all, so neither `::part(field)` nor `::part(field-)` ever matches * one -- its only rendered surface is its active-filter `chip`. * @csspart end - Wrapper around the `end` slot; hidden while nothing is slotted. * @csspart filter-control - One filter's composed built-in control, or the wrapper around a * custom renderer's control (and around a `'checkbox-menu'`'s dropdown plus its error line). * @csspart filter-control-label - A built-in control's label element. On a `'checkbox-menu'` this * is the trigger button's own label text rather than a stacked label above the control, and it * is visually hidden (never removed) under `labelVisibility: 'hidden'` -- except in the one case * where the trigger's selection summary already IS the label (hidden routing, no declared * `placeholder`, nothing selected), where it is omitted rather than naming the button twice. * Under `labelVisibility: 'auto'` this component clips the same element itself once the bar's own * allocation drops below `30rem`, and leaves it untouched above that -- so a consumer rule * targeting this part sees a visible element at a wide allocation and a hairline, still-named one * at a narrow one. * @csspart filter-control-label-group - A `'checkbox-menu'` trigger's composed ``'s own * label wrapper: the flex row laying out `filter-control-label` and `filter-control-input` * beside each other and, with `with-caret`, growing to fill the stretched trigger so its content * starts at the leading edge instead of centring. No other filter type renders this part -- every * other type's label and input are two independent elements with no shared wrapper of their own. * @csspart filter-control-field - A built-in control's field frame: select trigger, combobox * container, text/date input wrapper, or a `'checkbox-menu'` trigger button's own frame (the * element inside `` that draws the border, background and radius -- not the * chrome-less button host). * @csspart filter-control-input - A built-in control's display or editable input, or a * `'checkbox-menu'` trigger's selection summary. * @csspart filter-control-start - A built-in control's start adornment wrapper, including a * `'checkbox-menu'` trigger button's own. * @csspart filter-control-end - A built-in control's end adornment wrapper. * @csspart filter-control-listbox - A select or combobox options popover, or a * `'checkbox-menu'`'s popup surface. * @csspart filter-control-option - A select or combobox option row, or a `'checkbox-menu'`'s * `role="menuitemcheckbox"` row. * @csspart filter-control-tags - A combobox's multi-select tag container. * @csspart filter-control-tag - A combobox's individual selected tag. * @csspart filter-control-tag-label - A combobox tag's wrapping/ellipsis-safe label; capped by * that control's own `--tag-max-size`. * @csspart filter-control-tag-remove-button - A combobox tag's own remove button. * @csspart filter-control-tag-remove-button-base - Compatibility name for the icon wrapper inside * a combobox tag's remove button; the same reach a standalone `lr-combobox`/`lr-select` consumer * already has. * @csspart filter-control-clear-button - A built-in control's clear action, when rendered. * @csspart filter-control-expand-button - A date input's calendar-popup action. * @csspart filter-control-expand-icon - A select, combobox, or date-input expansion icon, or a * `'checkbox-menu'` trigger's own `with-caret` disclosure chevron. * @csspart filter-control-popup - A date input's positioned calendar popup. * @csspart filter-control-error - A built-in control's validation message. A `'checkbox-menu'` * renders this one itself (its composed dropdown has no error chrome), `aria-hidden` because the * same text also joins the trigger's accessible name -- an idref cannot cross into that button's * own shadow root. * @csspart filter-control-hint - A built-in control's hint message. * @csspart reset-button - The reset ``. * @csspart status - The loading ``, only rendered while `loading`. * @csspart active-filters - The `role="group"` wrapper around the active-filter chip row, only * rendered while `activeFiltersDisplay` admits at least one currently-active filter (never, for * `'hidden'`). * @csspart chips - The `` inside `active-filters`. * @csspart chip - One active-filter ``. * @cssprop [--lr-filter-bar-field-basis=var(--lr-size-12rem)] - Flex-basis of each filter's * `field` wrapper, controlling how many fields fit per row before the row wraps. * @cssprop [--lr-filter-bar-gap=var(--lr-space-s)] - Gap between filter fields, the `end` slot, * the reset button, and the loading status in the `controls` row. * @status stable * @since 4.1.0 */ export declare class LyraFilterBarextends LyraElement>{static styles:import("lit").CSSResultGroup[];protected static readonly immutableEventDetails:readonly string[];static properties:{filters:{attribute:boolean;noAccessor:boolean;};value:{attribute:boolean;noAccessor:boolean;};}; /** Accessible-name fallback for the root `role="group"` wrapper when the host has no * `aria-label`, matching ``. Attribute presence wins, including an * explicitly empty `aria-label`. */ label:string; /** Disables every composed filter control and the reset button. Plain property -- see the * class doc for why this component isn't form-associated / fieldset-cascaded. */ disabled:boolean; /** Shows the `status` spinner. Purely presentational -- filters stay editable while `loading`, * since a host typically wants a user to keep refining filters while a previous query is * still in flight; only the reset button (which would otherwise race a fresh, unrequeried * reset against an in-flight fetch for the *previous* value) is disabled by it. */ loading:boolean; /** Which currently-active filters render as removable chips in the row below the fields. * `'all'` (default, and the only behaviour this component had before this property existed) * shows one chip per filter that is not empty -- including a filter sitting at its own * `defaultValue`, since a declared default is itself a value the filter currently holds. * `'changed'` shows a chip only for a filter whose current value differs from its own * `defaultValue` (see `filterValueEqualsDefault`) -- so a bar whose defaults narrow the view on * load does not claim the user narrowed it, while a filter with no declared `defaultValue` * counts as changed the moment it has any value at all, since there is nothing for it to still * equal. `'hidden'` never renders the row, regardless of any filter's state. Every value other * than `'changed'`/`'hidden'` (including a foreign attribute value) behaves like `'all'`, * matching `labelVisibility`'s own foreign-value handling. Removing a chip always clears that * filter, exactly as it always has -- this property only changes which already-active filters * get a chip in the row, never what removing one does. * * `'changed'` additionally gates the reset button on `hasChangedFilters` rather than * `hasActiveFilters`, so an untouched defaults-only bar -- which renders no chip in this mode -- * no longer offers an enabled reset that would change nothing. `hasActiveFilters` itself is * unaffected by this property in every mode, and so is reset enablement under `'all'`/`'hidden'`. */ activeFiltersDisplay:LyraFilterBarActiveFiltersDisplay; /** Filters that have been visited (focusout'd) at least once -- gates only the *visual* * inline-error presentation on each composed control, matching every other form control in * this library (`lr-select`/`lr-combobox`/`lr-tool-param-form` all avoid flashing red before * the user has touched anything). */ private touchedFilters; /** Tracks whether the host-supplied `end` slot carries real content, so its wrapper part can * stay `hidden` (and claim no layout space) while unused. */ private readonly slotPresence;private _filters;private _value; /** The last value passed to the `value` setter, cloned but NOT yet filtered down to the filter * ids known at that moment. `filters`'s setter re-derives `_value` from this (not from the * already-filtered `_value`) so a `value` assignment landing before its matching `filters` * assignment -- same microtask/script order, or the same Lit template's binding order -- never * permanently drops fields for filters that simply hadn't been declared yet. */ private rawValue;private debounceControllers;private chipFocusGeneration;private lastValidityKey;private schemaGeneration;private schemaAbortController?; /** Host-declared filter definitions, rendered in array order. The first 10,000 definitions and * nested collection entries are deeply snapshotted and frozen; reassign after changing them. * `null`/`undefined` is treated as an empty array rather than throwing. Choice options require * string value/label data fields; malformed entries are omitted independently. Custom definitions * require a callable renderer and adapter. Exceptions thrown by admitted renderers propagate. * * `Defs` narrows this element's `value` to a keyed record typed per `filterId` -- see * `LyraFilterBarValueFor`; the unnarrowed default resolves to the published `readonly * LyraFilterBarFilterDefinition[]` below, which is why the manifest type is pinned here rather * than left to the class's own type parameter. * @type {readonly LyraFilterBarFilterDefinition[]} */ get filters():Defs;set filters(next:Defs|null|undefined); /** The current value of every filter -- see the class doc's serialization contract. Reads and * writes clone and freeze the record and each string-array field, bounded to 10,000 keys and * 10,000 array entries, so mutations never affect this component's state or a subsequent * `lr-input` detail. Reassign after changes. `null`/`undefined` writes clear to the canonical * empty record while reads stay non-null. * * `LyraFilterBarValueFor` narrows each key to the value type the matching entry in * `filters` implies (see `LyraFilterBarDefinitionValue`) when this element is typed with a * literal `Defs`; the unnarrowed default resolves to the published record below, which is why * the manifest type is pinned here rather than left to the inferred alias name. * @type {LyraFilterBarValue} */ get value():LyraFilterBarValueFor;set value(next:LyraFilterBarValueFor |null|undefined);private renewSchemaContext;private get schemaSignal();private isEmpty;private valueFor;private normalizeValue; /** Whether any filter currently has a value -- including one sitting at its own declared * `defaultValue`, which is a value the filter holds like any other. Also what gates whether the * `active-filters` chip row renders at all, and the reset button's own disabled state in every * `activeFiltersDisplay` mode except `'changed'`, where `hasChangedFilters` gates it instead. * This getter itself is unaffected by `activeFiltersDisplay`. */ get hasActiveFilters():boolean; /** Whether one filter's current value differs from its own declared `defaultValue`, using * `filterValueEqualsDefault` -- the exact equality `activeFiltersDisplay: 'changed'` already * filters its chip row on, not a second comparison. * * The `defaultIsSet` guard is what keeps a *pristine* filter out of the changed set: a filter * declaring no meaningful default has nothing to still equal, so "changed" can only mean "holds * a value". Reading that case through the raw equality instead would report a pristine bar as * changed whenever a filter's cleared reading is a non-`undefined` sentinel -- a `'chip'` * definition's own `clearValue` (`''` by default), or a `'custom'` adapter's. */ private filterIsChanged; /** Whether any filter's value differs from its own declared `defaultValue`. Always live, never * cached, exactly like `invalidFilterIds`. * * This is the counterpart to `hasActiveFilters`, not a synonym: a bar whose every filter sits * at a non-empty declared default reads `hasActiveFilters === true` (those defaults are real * values, and each one still renders its own chip under `activeFiltersDisplay: 'all'`) and * `hasChangedFilters === false` -- a bar whose defaults narrow the view on load does not claim * the user narrowed it. A filter with no declared `defaultValue` counts as changed the moment it * holds any value at all, since there is nothing for it to still equal; conversely, clearing a * filter that *does* declare one counts as changed too, because `reset()` would restore it. * * It differs from the `'changed'` chip row in exactly that last case: the row only ever * considers filters that currently hold a value, so a cleared-but-defaulted filter shows no * chip while still reading as changed here. */ get hasChangedFilters():boolean; /** What the reset button's own enablement keys on: whether pressing it would change anything. * Under `activeFiltersDisplay: 'changed'` -- the mode whose whole premise is that a value * sitting at its own declared default is not something the user applied -- that is * `hasChangedFilters`, so an untouched defaults-only bar offers no reset to press (and shows no * chip to remove either, which is the state the enabled button used to contradict). Every other * mode keeps `hasActiveFilters`, byte for byte what this component has always gated on. */ private get hasResettableFilters(); /** Filter ids currently failing their own `required` check -- a filter is invalid only when * `required` is set and its value is unset (see `isSet`). Always live, never cached. */ get invalidFilterIds():readonly string[]; /** Whether every `required` filter currently has a value. Never reveals inline errors on its * own -- see `reportValidity()`. */ checkValidity():boolean; /** Like `checkValidity()`, but also marks every currently-invalid filter as touched so its * inline error becomes visible immediately -- the hook a consumer's own "Apply"/search action * should call right before acting, mirroring ``'s identical method. */ reportValidity():boolean; /** Resets every filter to its own `defaultValue` (or unset, if it declared none), clears * touched state, and emits both `lr-input` (the standard "value changed" event, so a listener * that only listens for that still observes the reset) and `lr-reset` -- mirrors * ``'s own `clear()`, which likewise emits its standard value events *plus* a * dedicated `lr-clear`. */ reset():void;private get resetValue();private setFilterValue;private setCustomContextValue;private markTouched; /** Whether `delay` is a real, positive debounce -- non-finite/zero/negative means "no debounce" * rather than scheduling a timer that would never behave sensibly. Shared by `'text'` and * `'combobox'`. */ private isDebounced; /** Parks `value` under `id` and (re)starts its commit timer -- the shared mechanics behind * `'text'`'s per-keystroke debounce, `'combobox'`'s per-selection-change debounce, and * `'custom'`'s optional debounce. `commit` defaults to the built-in types' unconditional * `setFilterValue(id, pending)`; `'custom'` overrides it with `setCustomContextValue`'s extra * schema-generation/abort/connected guard, since -- unlike a built-in control -- a custom * renderer's closures can otherwise outlive the schema that created them. */ private scheduleDebounce; /** Whether that field currently holds an uncommitted edit -- i.e. the user is mid-edit and owns * the control (and its caret) until they pause, blur, or commit. */ private hasPendingDebounce;private onControlChange; /** Built-in controls keep their native-style `input`/`change` compatibility path, but their * prefixed aliases carry the child control's detail shape and must not impersonate this bar's * single full-value `lr-input` contract at the host boundary. */ private stopControlAlias;private onCustomControlChange; /** A `'text'` filter's keystroke: commits immediately, or (with a positive `debounce`) parks the * value until the user pauses. */ private onTextInput; /** Commits an in-flight keystroke/selection right now, ahead of its own delay -- the field's own * `change`, or its blur. A no-op when nothing is pending, so it is safe to call on every blur. * The settle callback drops the map entry, so a flushed field is left in the same state a * naturally-settled one is: no controller, nothing pending. */ private flushDebounce; /** Discards an in-flight keystroke/selection without committing it -- one filter's, or (with no * argument) every filter's. `syncTextControls()` then pushes the authoritative value back into * an uncontrolled `'text'` field on the next render (a `'combobox'` field's own `.value=` * binding reverts on its own, being fully controlled), so the discarded draft does not linger * on screen either. */ private cancelDebounce;private onFieldFocusout;private repairFocusAfterChipRemoval;private clearFilter;private displayValueFor; /** The filters `render()`'s chip row shows -- every non-empty filter under `'all'` (the * default), only those whose value differs from their own `defaultValue` under `'changed'`, or * none at all under `'hidden'` -- see `activeFiltersDisplay`. `clearFilter()`'s own focus-repair * index is computed against this same list, so it always matches the chips actually rendered * regardless of display mode. */ private get activeEntries(); /** Every `'text'` filter's debounce dies with the element. Without this a detached filter bar * would still fire its timer and emit `lr-input` after teardown; a re-parent (which also runs * this) simply drops the uncommitted keystroke, which the next keystroke or blur re-commits. */ disconnectedCallback():void; /** Closes every composed `'checkbox-menu'` dropdown outright. `` deliberately * *suspends* rather than closes on disconnect, so a filter bar moved between containers would * otherwise come back with a menu the user never reopened -- the same transient-state reset * this component already does for an in-flight debounce and the custom-renderer schema. Closing * on both edges covers the case where the detached update lands too late to take effect. */ private closeCheckboxMenus;connectedCallback():void; /** Pushes an *external* `value` change back into each uncontrolled `'text'` field -- a host * write, a chip removal, a `reset()`. Skipped entirely while that field has a debounce in * flight: the user is mid-edit and owns the field (and its caret) until they pause. */ private syncTextControls;protected willUpdate(changed:PropertyValues):void;protected updated(changed:PropertyValues):void; /** Optional decorative leading visual, rendered into a composed control's own leading slot as * inert, aria-hidden chrome so it can neither take focus nor join that control's accessible * name. Shared by ``'s own `icon` (select/combobox rows), a built-in filter * definition's own `icon` (the composed field itself), and the `'checkbox-menu'` rows -- whose * composed `` names its leading slot `icon` rather than `start`, which is why * the slot name is a parameter instead of a constant. */ private renderStartAdornment; /** One ``, shared by the select and combobox branches so an option's optional `icon` * reaches both and `searchText` reaches the one control that reads it (``; see * `LyraFilterBarOption.searchText`). */ private renderOption; /** The label/placeholder/accessible-name triple one composed control receives, resolved from * `labelVisibility`. Hiding the label routes it to the control's own `aria-label` (which every * composed control here honours over its computed internal name) and, when the definition * declares no `placeholder` of its own, also uses it as the placeholder -- so the field still * reads as itself once the stacked label is gone. * * `'auto'` deliberately resolves to the SAME triple as `'visible'`, not to the hidden branch. * Under `'auto'` the visible label element still exists at every width -- the narrow state only * clips it visually (see `labelAutoAttribute()`) -- so routing the name onto the control as well * would name a wide-allocation field twice, and a *narrow* one twice over too, since the clipped * label is still in the accessibility tree. Anything other than `'hidden'` (including a foreign * value) therefore keeps the visible routing, matching `activeFiltersDisplay`'s own * foreign-value handling. */ private labelRouting; /** Marks a filter's rendered control as label-auto for `filter-bar.styles.ts`'s container query, * which is what actually clips the label below the threshold. An attribute rather than a class * because the same hook has to be readable from a rule reaching into the composed control's own * shadow root -- `[data-label-auto]::part(form-control-label)` -- where a class on the host * would work equally well but an attribute matches this component's existing `data-filter-id` * marker. Absent for every other `labelVisibility`, so an unset filter renders byte-identical * markup to before this option existed. */ private labelAutoAttribute; /** A `'checkbox-menu'` row was activated. The composed `` fires this * cancelable event with its *proposed* next `checked` state and commits that state itself * unless the event is prevented -- so this handler always prevents it and derives the next * `string[]` from the bar's own value instead. Without that, the row would self-toggle and the * `?checked=` binding's dirty check would see no change on the next render, permanently * desynchronizing a rejected toggle (a `disabled` bar, a removed filter) from the rendered * checkmark. */ private onCheckboxMenuToggle; /** The `'checkbox-menu'` branch: `` plus one `` * per option. The menu deliberately stays open across toggles (`stay-open-on-select`), which is * the whole interaction difference from a combobox. Unlike every other built-in branch the * composed control brings no label/error chrome of its own, so this renders the only copy of * each: the label as the trigger's own text (visually hidden, never removed, when * `labelVisibility` is `'hidden'`), and the revealed required error both as a visible, * `aria-hidden` line under the field and as a screen-reader-only run inside the trigger -- an * idref cannot reach the trigger's own internal button across that shadow boundary, so joining * the button's accessible name is the only way the error reaches assistive tech. * * The label and the selection summary are two separate runs slotted into ONE `` * label wrapper. lr-button's own `gap` sits between its start/label/end wrappers, not inside the * label, so left alone the two runs concatenate ("TeamsCore and Design"); `filter-bar.styles.ts` * lays that wrapper out as a flex row with its own gap instead. Under * `labelVisibility: 'hidden'` with no declared `placeholder`, `labelRouting()` deliberately * falls back to the label itself as the summary so the trigger still reads as itself once the * stacked label is gone -- and the screen-reader-only label run is then dropped, because * emitting both would name the button twice ("Teams Teams"). * * Two affordances every other built-in type inherits from its composed control are deliberately * absent here, for mechanical reasons rather than editorial ones: * * - **No `aria-invalid` on the trigger.** `` forwards exactly six host ARIA * attributes onto the internal element that owns the button role (`aria-label`, * `aria-haspopup`, `aria-expanded`, `aria-pressed`, `aria-current`, `aria-describedby`); * `aria-invalid` is not one of them, so writing it here would leave it on a role-less * `display: inline-block` host where no assistive technology would ever read it. A * silently-inert ARIA attribute is worse than none, and the revealed error already reaches * assistive tech through the trigger's accessible name. * - **No required marker.** `formControlRequiredMarker` (`internal/form-control.styles.ts`) * carries the library's only two marker shapes -- `:host([required]) * [part~='form-control-label']` and `[part='field'][data-required] [part='label']` -- and * neither matches this structure: the host is not the required field, and this trigger's label * part is `filter-control-label`. Re-typing the `::after` locally is precisely what that * shared sheet exists to prevent, and renaming the span to `label`/`form-control-label` to fit * would mint a permanent public part name on `` for a styling side effect. * - **No stacked label above the field.** Every other built-in type's stacked label is rendered * by the COMPOSED control itself (its own `form-control-label`, fed by this component's * `.label=` binding) -- there is no shared "stacked label" template inside `` * for this branch to opt into without inventing one. `labelVisibility` therefore keeps its * existing, narrower meaning here (whether the label baked into the trigger's own text is * visible or screen-reader-only), not "stacked vs. inline". Revisit only once a concrete * layout is designed for it, rather than approximating one here. * * The trigger DOES get the same `with-caret` disclosure chevron a `'select'`'s own trigger * shows, both because a menu button with no expand indicator otherwise reads as a * call-to-action rather than a field, and because ``'s own `with-caret` layout (the * label grows to fill the stretched button, pinning the caret to the trailing edge -- see * `button.class.ts`) is what left-aligns this trigger's content instead of centring it: no new * layout of this component's own is involved. `label`/`caret` are forwarded from the composed * `` under collision-resistant `filter-control-*` names -- `filter-control-label` and * `filter-control-input` already name this component's OWN two spans rendered inside that label * wrapper, so the wrapper itself needs a third, distinct name * (`filter-control-label-group`) rather than colliding with either; the caret reuses * `filter-control-expand-icon`, the same name a select/combobox/date-input's own disclosure * chevron already forwards to, so one consumer rule styles every filter type's chevron. */ private renderCheckboxMenu;private renderControl;private rendersValidationError;render():TemplateResult;}declare global{interface HTMLElementTagNameMap{'lr-filter-bar':LyraFilterBar;}}export{};