import * as _angular_core from '@angular/core'; import { Signal } from '@angular/core'; import { NestedKeyOf, Operator, Filter } from '@sdcorejs/utils/models'; import { MatMenu } from '@angular/material/menu'; import { SdSearch } from '@sdcorejs/angular/forms/models'; type SdQueryFieldType = 'string' | 'number' | 'boolean' | 'date' | 'datetime' | 'values' | 'lazy-values'; interface SdQueryFieldBase { /** Dot-notation field path (matches `Filter.field`). */ key: NestedKeyOf; /** Human-readable label shown on chip + field picker. */ label: string; /** Material icon name; falls back to `SD_QUERY_TYPE_ICON[type]` then `'tune'`. */ icon?: string; /** * Controls the operator selector in the chip popover: * - omitted / `false` → **simple mode**: no operator dropdown; the chip always uses * `defaultOperator` (or the per-type default). Use this for screens that don't need * operator choice. * - `true` → show the full operator set for the field's `type` * (`SD_QUERY_OPERATORS_BY_TYPE[type]`). * - `Operator[]` → show exactly these operators. */ operators?: boolean | Operator[]; /** * Operator the chip starts with. Falls back to `SD_QUERY_DEFAULT_OPERATOR_BY_TYPE[type]`: * string→CONTAIN, number→EQUAL, values/lazy-values→IN, boolean→EQUAL, date/datetime→BETWEEN. */ defaultOperator?: Operator; /** Field is offered in picker but not interactive (read-only badge in chip). */ disabled?: boolean; } interface SdQueryFieldString extends SdQueryFieldBase { type: 'string'; } interface SdQueryFieldNumber extends SdQueryFieldBase { type: 'number'; /** Bounds for the input control inside the chip popover. */ min?: number; max?: number; /** Step for the number input. */ step?: number; } interface SdQueryFieldBoolean extends SdQueryFieldBase { type: 'boolean'; /** Labels rendered for the true/false buttons. Default: "Có" / "Không". */ trueLabel?: string; falseLabel?: string; } interface SdQueryFieldDate extends SdQueryFieldBase { type: 'date' | 'datetime'; /** Restrict the picker calendar to this range. */ min?: Date | string; max?: Date | string; } /** * Statically-known options (sync array, signal, or one-shot promise). * Mirrors `SdTableColumnValues.option`. */ interface SdQueryFieldValues> extends SdQueryFieldBase { type: 'values'; option: { items: K[] | Signal | (() => Promise); valueField: NestedKeyOf; displayField: NestedKeyOf; }; } /** * Server-backed options — searchable, paginated. Mirrors `SdTableColumnLazyValues.option`. * `search` is the unified `SdSearch` callback used by `sd-select`: it handles * `{ type: 'SEARCH', searchText }` for live queries and `{ type: 'VALUE', value }` for * resolving chip-display labels of already-selected IDs. */ interface SdQueryFieldLazyValues> extends SdQueryFieldBase { type: 'lazy-values'; option: { search: SdSearch; valueField: NestedKeyOf; displayField: NestedKeyOf; }; } type SdQueryField = SdQueryFieldString | SdQueryFieldNumber | SdQueryFieldBoolean | SdQueryFieldDate | SdQueryFieldValues | SdQueryFieldLazyValues; type SdQueryLogic = 'AND' | 'OR'; interface SdQuery { filters: Filter[]; /** Global connector between filters. Defaults to `'AND'`. */ logic?: SdQueryLogic; /** Free-text search box (only present when `showSearch=true`). */ search?: string; } interface SdQueryBarOption { /** Prefix for auto-generated `data-autoid` on inner controls. */ autoId?: string; /** Available fields the user can filter by. */ fields: SdQueryField[]; /** Initial active filter chips. */ filters?: Filter[]; /** Initial global connector between filters. */ logic?: SdQueryLogic; /** Initial free-text search string. */ search?: string; mode?: 'popover' | 'inline'; density?: 'compact' | 'comfortable'; showSearch?: boolean; showSavedFilters?: boolean; savedFiltersKey?: string; showLogicToggle?: boolean; showClearAll?: boolean; showOperatorOnChip?: boolean; onQueryChange?: (query: SdQuery) => void; onApply?: (query: SdQuery) => void; } /** Persisted bookmark of a query (filters + logic + search) — managed by `[savedFiltersKey]`. */ interface SdSavedFilter { id: string; name: string; query: SdQuery; } /** * Transient state of the in-progress chip during inline-mode token build (field → * operator → value). Lives at the parent (`SdQueryBar.building()`) and is rendered * by ``. Step transitions: * - 'operator' — operator menu open, waiting for the user to pick a condition * - 'value' — operator locked, value picker / seamless input is the focus */ interface BuildingChip { field: SdQueryField; operator?: Operator; step: 'operator' | 'value'; value?: unknown; } /** Full operator set per field type — used when `operators: true`. */ declare const SD_QUERY_OPERATORS_BY_TYPE: Record; /** Default operator when a chip is created and `field.defaultOperator` is not set. */ declare const SD_QUERY_DEFAULT_OPERATOR_BY_TYPE: Record; /** Icon fallback per field type when `SdQueryField.icon` is not set. */ declare const SD_QUERY_TYPE_ICON: Record; /** * Resolves the icon shown on chips and in the field picker. * Priority: `field.icon` → `SD_QUERY_TYPE_ICON[field.type]` → `'tune'`. */ declare function sdQueryFieldIcon(field: SdQueryField): string; /** Operators that carry no data — value section is hidden in chip popover. */ declare const SD_QUERY_NO_DATA_OPERATORS: Operator[]; /** Operators that carry an array payload — UI offers multi-select. */ declare const SD_QUERY_MULTI_OPERATORS: Operator[]; /** Picks the initial operator when a new chip is created for `field`. */ declare function sdQueryDefaultOperator(field: SdQueryField): Operator; /** * Operators offered in the chip popover for `field`: * - `operators === true` → full set for the type * - `operators` is an array → that array (deduped against the type set is the caller's job) * - otherwise (simple mode) → just the single default operator (no real choice) */ declare function sdQueryAllowedOperators(field: SdQueryField): Operator[]; /** * Whether the operator selector should be visible. Simple mode (operators omitted/false, * or an array with a single entry) hides the dropdown — the chip uses one fixed operator. */ declare function sdQueryShowOperatorSelector(field: SdQueryField): boolean; /** * Popover-mode chip editor — the entire `` that opens when a popover-mode * chip is clicked. Owns ALL operator+value staging signals and async option loading. * * why: tách khỏi `` để parent chỉ giữ `editingIndex` (chip nào đang * mở) + nhận `(commit)` khi popover đóng. Mỗi lần parent gọi `seed(filter, field)` * trước khi mở chip popover, child reset staging signals + kích option loading. * * Public surface (template ref `#cp`): * - `cp.menu()` — the `` to feed `[menu]` of `` * - `cp.seed(filter, field)` — parent reseeds staging before opening * - `(commit)` output — emitted on mat-menu close with staged Filter * - `(swapField)` output — emitted when the nested field switcher picks a new field */ declare class SdQueryChipPopover { #private; /** Resolved field of the currently editing chip — parent passes from `fieldByKey()`. */ readonly field: _angular_core.InputSignal; /** The chip's current Filter — used by `seed()` for initial staging values. */ readonly filter: _angular_core.InputSignal; /** Optional chip index — embedded in the composed autoIds. */ readonly chipIndex: _angular_core.InputSignal; /** Prefix for `data-autoId` on inner controls. */ readonly autoIdBase: _angular_core.InputSignal; /** MatMenu for the field switcher — parent passes its `` menu. */ readonly switchPickerMenu: _angular_core.InputSignal; /** Emitted when mat-menu closes — parent splices `next` into filters[idx]. */ readonly commit: _angular_core.OutputEmitterRef; /** Emitted when nested field-switcher picks a new field — parent calls changeFilterField. */ readonly swapField: _angular_core.OutputEmitterRef; /** Staged operator. */ readonly editingOperator: _angular_core.WritableSignal; /** Staged value (shape depends on field type + operator). */ readonly editingValue: _angular_core.WritableSignal; /** Resolved option list for values / lazy-values. */ readonly editingOptions: _angular_core.WritableSignal; /** Loading flag for async option fetch. */ readonly editingOptionsLoading: _angular_core.WritableSignal; readonly allowedOperators: _angular_core.Signal; readonly showOperatorSelector: _angular_core.Signal; /** Whether the staged operator is multi-select (IN/NOT_IN). */ multiple(op?: Operator): boolean; /** Whether the staged operator carries no data (NULL/NOT_NULL). */ isNoDataOperator(op: Operator | string): boolean; /** Compose an autoId for an inner control (`-chip-`). */ chipAutoId(role: string): string; readonly iconFor: typeof sdQueryFieldIcon; readonly menu: _angular_core.Signal; /** Reseed staging from a new filter/field pair — call before opening the menu. */ seed(filter: Filter | undefined, field: SdQueryField | undefined): void; /** Called on operator change in the popover header — reshapes value when family changes. */ onEditingOperatorChange(next: Operator): void; /** Single-value input change. */ onEditingValueInput(value: unknown): void; /** BETWEEN range — mutate only `.from`. */ onEditingRangeFrom(value: string | number | null): void; /** BETWEEN range — mutate only `.to`. */ onEditingRangeTo(value: string | number | null): void; /** Toggle a value in the staged multi-select array. */ toggleEditingMultiValue(value: unknown): void; isEditingMultiSelected(value: unknown): boolean; /** * mat-menu's (closed) handler — compose the next Filter from staging signals and * emit (commit). Parent splices into its filters[] and nulls editingIndex. */ onMenuClosed(): void; static ɵfac: _angular_core.ɵɵFactoryDeclaration; static ɵcmp: _angular_core.ɵɵComponentDeclaration; } /** * Compact popover-mode chip face. Click → opens the parent-supplied [menu] (mat-menu * containing the chip editor). Inert div[role=button] so the nested * doesn't end up as a button-in-button (invalid HTML). */ declare class SdQueryPopoverChip { /** Resolved field (from the bar's `fieldByKey()` map). `undefined` → render raw key. */ readonly field: _angular_core.InputSignal; /** The chip's filter — used to read `field` / `operator` / `data` for display text. */ readonly filter: _angular_core.InputSignal; /** "Active" = chip has a real value or is no-data op. Drives layout + colour. */ readonly active: _angular_core.InputSignal; /** Operator visible on the chip face (else hidden, ":" separator). */ readonly showOperator: _angular_core.InputSignal; /** Rendered value text for the value slot. */ readonly valueText: _angular_core.InputSignal; /** Chip popover mat-menu instance supplied by the parent. */ readonly menu: _angular_core.InputSignal; /** Fired when the chip popover opens (parent seeds its editing state). */ readonly open: _angular_core.OutputEmitterRef; /** Fired when the user clicks the × removal icon. */ readonly remove: _angular_core.OutputEmitterRef; readonly iconFor: typeof sdQueryFieldIcon; filterField(): string; filterOperator(): Operator; private readonly trigger; openMenu(): void; closeMenu(): void; static ɵfac: _angular_core.ɵɵFactoryDeclaration; static ɵcmp: _angular_core.ɵɵComponentDeclaration; } type Density = 'compact' | 'comfortable'; declare class SdQueryBar { #private; /** All popover-mode chips in order — used to auto-open after addFilter / close before removeFilter. */ readonly popoverChips: _angular_core.Signal; /** The extracted in-progress chip — owns operator menu + value picker view refs. */ private readonly buildChip; /** The extracted chip popover — owns operator+value staging + commit-on-close. */ readonly chipPopover: _angular_core.Signal; /** Main option object. Prefer this API for new usage; individual inputs stay as a migration bridge. */ readonly option: _angular_core.InputSignal | undefined>; /** Prefix for auto-generated `data-autoid` on inner controls (chips, operator/value editors, buttons). */ readonly autoIdInput: _angular_core.InputSignalWithTransform; /** Available fields the user can filter by. Required for the field picker. */ readonly fields: _angular_core.InputSignalWithTransform; /** * Active filter chips. Two-way bindable via `[(filters)]`. * Use this when you only need a flat `Filter[]` (no global logic / search box). */ readonly filters: _angular_core.ModelSignal; /** * Global connector between filters. Two-way bindable via `[(logic)]`. * Only meaningful when `showLogicToggle=true` and there are ≥2 filters. */ readonly logic: _angular_core.ModelSignal; /** Free-text search string. Two-way bindable via `[(search)]`. Only shown when `showSearch=true`. */ readonly search: _angular_core.ModelSignal; /** * Editing mode: * - `'popover'` (default) → compact chips; click a chip to edit operator + value in a * mat-menu popover, commit with "Áp dụng". * - `'inline'` → GitLab-style. Each filter's operator + value controls render directly * on the bar (no popup, no per-filter apply). Edits update `filters` live; the user * presses the search button (or Enter) once to fire `(apply)`. */ readonly mode: _angular_core.InputSignalWithTransform<"popover" | "inline", "popover" | "inline" | null | undefined>; /** Density preset — chip / control height. */ readonly density: _angular_core.InputSignalWithTransform; /** Show free-text search input on the left. */ readonly showSearch: _angular_core.InputSignalWithTransform; /** Show saved-filters dropdown on the right. Requires `[savedFiltersKey]` to actually persist. */ readonly showSavedFilters: _angular_core.InputSignalWithTransform; /** * Namespace key for persisting saved filters to `localStorage`. When set, the saved-filters * dropdown loads/saves under `sd-query-bar:savedFilters:`. Leave undefined to disable. */ readonly savedFiltersKey: _angular_core.InputSignal; /** * Snapshot of the current query — fed into `` so * saving a filter captures live filters/logic/search. */ readonly currentQuery: _angular_core.Signal>; /** Receive an applied filter from the saved-filters menu — re-install bar state + trigger apply. */ onApplyFilter(saved: SdSavedFilter): void; /** Show AND/OR segmented toggle (renders only when there are ≥2 filters). */ readonly showLogicToggle: _angular_core.InputSignalWithTransform; /** Show "Clear all" button when at least one filter is active. */ readonly showClearAll: _angular_core.InputSignalWithTransform; /** Render the operator label on the chip face (default: hidden — operator only visible in popover). */ readonly showOperatorOnChip: _angular_core.InputSignalWithTransform; /** Composite payload — emitted whenever filters / logic / search change. */ readonly queryChange: _angular_core.OutputEmitterRef>; /** Fires when the user presses "Áp dụng" inside a chip popover — host should reload data. */ readonly apply: _angular_core.OutputEmitterRef>; /** Map of `field.key` → `SdQueryField` for fast lookup from filters[]. */ readonly resolvedAutoId: _angular_core.Signal; readonly resolvedFields: _angular_core.Signal; readonly resolvedMode: _angular_core.Signal<"popover" | "inline">; readonly resolvedDensity: _angular_core.Signal; readonly resolvedShowSearch: _angular_core.Signal; readonly resolvedShowSavedFilters: _angular_core.Signal; readonly resolvedSavedFiltersKey: _angular_core.Signal; readonly resolvedShowLogicToggle: _angular_core.Signal; readonly resolvedShowClearAll: _angular_core.Signal; readonly resolvedShowOperatorOnChip: _angular_core.Signal; constructor(); readonly fieldByKey: _angular_core.Signal>; /** Field keys already chained on a chip — the picker greys these out. */ readonly usedFieldKeys: _angular_core.Signal>; /** Render the global AND/OR connector text between chips when `logic === 'OR'`. */ readonly showOrConnector: _angular_core.Signal; /** Search button is actionable only when there is something to apply. */ readonly canSearch: _angular_core.Signal; /** Index of the chip whose popover is open. Reset to null after commit / close. */ readonly editingIndex: _angular_core.WritableSignal; /** Resolved field of the chip whose popover is currently open (or null). */ readonly editingField: _angular_core.Signal; /** * Multi-select is derived from the operator (IN / NOT_IN) — not a field flag. * Only called by inline-mode + build-mode templates with a known operator; * popover-mode chips read `multiple()` from the child popover directly. */ multiple(op: Operator): boolean; readonly iconFor: typeof sdQueryFieldIcon; /** Chip is "active" when it has a non-empty value OR a no-data operator (NULL/NOT_NULL). */ isFilterActive(filter: Filter): boolean; /** Rendered value text on a chip. */ chipValueText(filter: Filter): string; isNoDataOperator(op: Operator | string): boolean; readonly building: _angular_core.Signal | null>; allowedOperatorsFor(field: SdQueryField): Operator[]; inlineAutoId(index: number, role: string): string; /** Entry point from the field picker — start building a chip for `field`. */ beginBuild(field: SdQueryField): void; /** Operator chosen during build — finish (no-data) or advance to the value step. */ pickBuildOperator(op: Operator): void; /** Value committed during build — push the completed chip, clear building. No emit. */ commitBuildValue(value: unknown): void; /** * Commit from the seamless build chip (string / number). An empty value (blur with no * input) cancels the build instead of pushing a blank chip. */ onBuildSeamlessCommit(value: unknown): void; /** Abandon the in-progress chip. */ cancelBuild(): void; /** * Commit both ends of a BETWEEN range at once — called from ``'s * `(commitRange)` output when the user picks a date range. * why: sd-date-range emits {from,to} via (sdChange) — single call thay cho cặp * setFilterRangeFrom / setFilterRangeTo cũ (đã bỏ). */ setFilterRange(i: number, ev: { from: unknown; to: unknown; } | null): void; addFilter(field: SdQueryField): void; /** Swap the field of an existing chip — reset operator + value to the new field's defaults. */ changeFilterField(index: number, field: SdQueryField): void; updateFilter(index: number, patch: Partial): void; updateFilterData(index: number, data: unknown): void; removeFilter(index: number): void; clearAll(): void; setLogic(value: SdQueryLogic): void; setSearch(value: string): void; triggerApply(): void; /** * Called when a popover-mode chip is clicked — set editingIndex and seed the * child popover's staging signals from the chip's Filter. */ openChipPopover(index: number): void; /** Receive `(commit)` from the child popover — splice into filters, null the index. */ onChipPopoverCommit(next: Filter): void; static ɵfac: _angular_core.ɵɵFactoryDeclaration; static ɵcmp: _angular_core.ɵɵComponentDeclaration; } export { SD_QUERY_DEFAULT_OPERATOR_BY_TYPE, SD_QUERY_MULTI_OPERATORS, SD_QUERY_NO_DATA_OPERATORS, SD_QUERY_OPERATORS_BY_TYPE, SD_QUERY_TYPE_ICON, SdQueryBar, sdQueryAllowedOperators, sdQueryDefaultOperator, sdQueryFieldIcon, sdQueryShowOperatorSelector }; export type { BuildingChip, SdQuery, SdQueryBarOption, SdQueryField, SdQueryFieldBoolean, SdQueryFieldDate, SdQueryFieldLazyValues, SdQueryFieldNumber, SdQueryFieldString, SdQueryFieldType, SdQueryFieldValues, SdQueryLogic, SdSavedFilter };