elastic-input 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +461 -0
- package/dist/autocomplete/AutocompleteEngine.d.ts +36 -0
- package/dist/autocomplete/suggestionTypes.d.ts +16 -0
- package/dist/components/AutocompleteDropdown.d.ts +24 -0
- package/dist/components/DatePicker.d.ts +9 -0
- package/dist/components/DateRangePicker.d.ts +16 -0
- package/dist/components/ElasticInput.d.ts +39 -0
- package/dist/components/HighlightedContent.d.ts +7 -0
- package/dist/components/ValidationSquiggles.d.ts +13 -0
- package/dist/constants.d.ts +18 -0
- package/dist/elastic-input.es.js +3670 -0
- package/dist/highlighting/parenMatch.d.ts +17 -0
- package/dist/highlighting/rangeHighlight.d.ts +10 -0
- package/dist/highlighting/regexHighlight.d.ts +10 -0
- package/dist/index.d.ts +18 -0
- package/dist/lexer/Lexer.d.ts +32 -0
- package/dist/lexer/tokens.d.ts +28 -0
- package/dist/parser/Parser.d.ts +37 -0
- package/dist/parser/ast.d.ts +97 -0
- package/dist/styles/inlineStyles.d.ts +19 -0
- package/dist/types.d.ts +383 -0
- package/dist/utils/cursorUtils.d.ts +16 -0
- package/dist/utils/dateUtils.d.ts +8 -0
- package/dist/utils/domUtils.d.ts +19 -0
- package/dist/utils/expandSelection.d.ts +20 -0
- package/dist/utils/extractValues.d.ts +26 -0
- package/dist/utils/smartSelect.d.ts +13 -0
- package/dist/utils/textUtils.d.ts +57 -0
- package/dist/utils/undoStack.d.ts +23 -0
- package/dist/validation/Validator.d.ts +39 -0
- package/dist/validation/dateValidator.d.ts +1 -0
- package/dist/validation/numberValidator.d.ts +1 -0
- package/package.json +74 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Token } from '../lexer/tokens';
|
|
2
|
+
|
|
3
|
+
export interface ParenMatch {
|
|
4
|
+
openStart: number;
|
|
5
|
+
closeStart: number;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Find matching parenthesis pair based on cursor position.
|
|
9
|
+
*
|
|
10
|
+
* Follows standard IDE bracket matching rules (VS Code / JetBrains):
|
|
11
|
+
* 1. Check "after" first: if the character immediately before the cursor is a paren,
|
|
12
|
+
* that paren and its match are highlighted.
|
|
13
|
+
* 2. Then check "before": if the character at the cursor position (right of caret) is a paren,
|
|
14
|
+
* that paren and its match are highlighted.
|
|
15
|
+
* 3. "After" (left of caret) takes precedence.
|
|
16
|
+
*/
|
|
17
|
+
export declare function findMatchingParen(tokens: Token[], cursorOffset: number): ParenMatch | null;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Token } from '../lexer/tokens';
|
|
2
|
+
import { ColorConfig } from '../types';
|
|
3
|
+
|
|
4
|
+
export type RangePartType = 'bracket' | 'toKeyword' | 'bareValue' | 'quotedValue' | 'wildcard' | 'whitespace';
|
|
5
|
+
export interface RangePart {
|
|
6
|
+
type: RangePartType;
|
|
7
|
+
text: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function tokenizeRangeContent(value: string): RangePart[];
|
|
10
|
+
export declare function buildRangeHTML(token: Token, colors: Required<ColorConfig>): string;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Token } from '../lexer/tokens';
|
|
2
|
+
import { ColorConfig } from '../types';
|
|
3
|
+
|
|
4
|
+
export type RegexPartType = 'delimiter' | 'charClass' | 'groupOpen' | 'groupClose' | 'escape' | 'quantifier' | 'anchor' | 'alternation' | 'text';
|
|
5
|
+
export interface RegexPart {
|
|
6
|
+
type: RegexPartType;
|
|
7
|
+
text: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function tokenizeRegexContent(value: string): RegexPart[];
|
|
10
|
+
export declare function buildRegexHTML(token: Token, colors: Required<ColorConfig>): string;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export { ElasticInput } from './components/ElasticInput';
|
|
2
|
+
export { buildHighlightedHTML } from './components/HighlightedContent';
|
|
3
|
+
export type { HighlightOptions } from './components/HighlightedContent';
|
|
4
|
+
export { Lexer } from './lexer/Lexer';
|
|
5
|
+
export type { LexerOptions } from './lexer/Lexer';
|
|
6
|
+
export { Parser } from './parser/Parser';
|
|
7
|
+
export { Validator } from './validation/Validator';
|
|
8
|
+
export { AutocompleteEngine } from './autocomplete/AutocompleteEngine';
|
|
9
|
+
export type { AutocompleteOptions } from './autocomplete/AutocompleteEngine';
|
|
10
|
+
export { extractValues } from './utils/extractValues';
|
|
11
|
+
export type { ExtractedValue, ExtractedValueKind } from './utils/extractValues';
|
|
12
|
+
export { DEFAULT_COLORS, DARK_COLORS, DEFAULT_STYLES, DARK_STYLES } from './constants';
|
|
13
|
+
export type { ElasticInputProps, ElasticInputAPI, FieldConfig, FieldsSource, FieldType, SavedSearch, HistoryEntry, SuggestionItem, ColorConfig, StyleConfig, ValidateValueContext, ValidationResult, ValidateReturn, TabContext, TabActionResult, DropdownConfig, FeaturesConfig, } from './types';
|
|
14
|
+
export type { Token, TokenType } from './lexer/tokens';
|
|
15
|
+
export type { ASTNode } from './parser/ast';
|
|
16
|
+
export type { CursorContext, CursorContextType } from './parser/Parser';
|
|
17
|
+
export type { ValidationError, ValidateValueFn } from './validation/Validator';
|
|
18
|
+
export type { Suggestion } from './autocomplete/suggestionTypes';
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Token } from './tokens';
|
|
2
|
+
|
|
3
|
+
export interface LexerOptions {
|
|
4
|
+
/** Recognize `#name` as SAVED_SEARCH tokens. @default false */
|
|
5
|
+
savedSearches?: boolean;
|
|
6
|
+
/** Recognize `!query` as HISTORY_REF tokens. @default false */
|
|
7
|
+
historySearch?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare class Lexer {
|
|
10
|
+
private input;
|
|
11
|
+
private pos;
|
|
12
|
+
private state;
|
|
13
|
+
private tokens;
|
|
14
|
+
private options;
|
|
15
|
+
constructor(input: string, options?: LexerOptions);
|
|
16
|
+
tokenize(): Token[];
|
|
17
|
+
private peek;
|
|
18
|
+
private peekAt;
|
|
19
|
+
private advance;
|
|
20
|
+
private isWhitespace;
|
|
21
|
+
private isAlpha;
|
|
22
|
+
private isAlphaNumeric;
|
|
23
|
+
private readWhitespace;
|
|
24
|
+
private readQuotedString;
|
|
25
|
+
private readTerm;
|
|
26
|
+
private readValue;
|
|
27
|
+
private readRangeValue;
|
|
28
|
+
private tryReadModifier;
|
|
29
|
+
private readRegex;
|
|
30
|
+
private readSavedSearch;
|
|
31
|
+
private readHistoryRef;
|
|
32
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export declare enum TokenType {
|
|
2
|
+
FIELD_NAME = "FIELD_NAME",
|
|
3
|
+
COLON = "COLON",
|
|
4
|
+
VALUE = "VALUE",
|
|
5
|
+
QUOTED_VALUE = "QUOTED_VALUE",
|
|
6
|
+
AND = "AND",
|
|
7
|
+
OR = "OR",
|
|
8
|
+
NOT = "NOT",
|
|
9
|
+
COMPARISON_OP = "COMPARISON_OP",
|
|
10
|
+
LPAREN = "LPAREN",
|
|
11
|
+
RPAREN = "RPAREN",
|
|
12
|
+
SAVED_SEARCH = "SAVED_SEARCH",
|
|
13
|
+
HISTORY_REF = "HISTORY_REF",
|
|
14
|
+
PREFIX_OP = "PREFIX_OP",
|
|
15
|
+
WILDCARD = "WILDCARD",
|
|
16
|
+
REGEX = "REGEX",
|
|
17
|
+
RANGE = "RANGE",
|
|
18
|
+
TILDE = "TILDE",
|
|
19
|
+
BOOST = "BOOST",
|
|
20
|
+
WHITESPACE = "WHITESPACE",
|
|
21
|
+
UNKNOWN = "UNKNOWN"
|
|
22
|
+
}
|
|
23
|
+
export interface Token {
|
|
24
|
+
type: TokenType;
|
|
25
|
+
value: string;
|
|
26
|
+
start: number;
|
|
27
|
+
end: number;
|
|
28
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Token } from '../lexer/tokens';
|
|
2
|
+
import { ASTNode, ErrorNode } from './ast';
|
|
3
|
+
|
|
4
|
+
export type CursorContextType = 'FIELD_NAME' | 'FIELD_VALUE' | 'OPERATOR' | 'RANGE' | 'SAVED_SEARCH' | 'HISTORY_REF' | 'EMPTY';
|
|
5
|
+
export interface CursorContext {
|
|
6
|
+
type: CursorContextType;
|
|
7
|
+
partial: string;
|
|
8
|
+
fieldName?: string;
|
|
9
|
+
token?: Token;
|
|
10
|
+
}
|
|
11
|
+
export declare class Parser {
|
|
12
|
+
private tokens;
|
|
13
|
+
private pos;
|
|
14
|
+
private nonWsTokens;
|
|
15
|
+
private errors;
|
|
16
|
+
constructor(tokens: Token[]);
|
|
17
|
+
getErrors(): ErrorNode[];
|
|
18
|
+
/** Check if a QUOTED_VALUE token is missing its closing quote. */
|
|
19
|
+
private isUnclosedQuote;
|
|
20
|
+
/** Strip quotes from a QUOTED_VALUE token, handling unclosed quotes correctly. */
|
|
21
|
+
private stripQuotes;
|
|
22
|
+
/** If the token is an unclosed quote, push an error. */
|
|
23
|
+
private checkUnclosedQuote;
|
|
24
|
+
parse(): ASTNode | null;
|
|
25
|
+
private peek;
|
|
26
|
+
private advance;
|
|
27
|
+
private match;
|
|
28
|
+
private parseOr;
|
|
29
|
+
private parseAnd;
|
|
30
|
+
private parseNot;
|
|
31
|
+
private applyGroupBoost;
|
|
32
|
+
private applyModifiers;
|
|
33
|
+
private parseRangeBound;
|
|
34
|
+
private parseRange;
|
|
35
|
+
private parsePrimary;
|
|
36
|
+
static getCursorContext(tokens: Token[], cursorOffset: number): CursorContext;
|
|
37
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
export type ASTNode = FieldValueNode | FieldGroupNode | BooleanExprNode | GroupNode | NotNode | SavedSearchNode | HistoryRefNode | BareTermNode | RegexNode | RangeNode | ErrorNode;
|
|
2
|
+
export interface FieldValueNode {
|
|
3
|
+
type: 'FieldValue';
|
|
4
|
+
field: string;
|
|
5
|
+
operator: string;
|
|
6
|
+
value: string;
|
|
7
|
+
quoted: boolean;
|
|
8
|
+
boost?: number;
|
|
9
|
+
fuzzy?: number;
|
|
10
|
+
proximity?: number;
|
|
11
|
+
start: number;
|
|
12
|
+
end: number;
|
|
13
|
+
}
|
|
14
|
+
export interface FieldGroupNode {
|
|
15
|
+
type: 'FieldGroup';
|
|
16
|
+
field: string;
|
|
17
|
+
expression: ASTNode;
|
|
18
|
+
boost?: number;
|
|
19
|
+
start: number;
|
|
20
|
+
end: number;
|
|
21
|
+
}
|
|
22
|
+
export interface BooleanExprNode {
|
|
23
|
+
type: 'BooleanExpr';
|
|
24
|
+
operator: 'AND' | 'OR';
|
|
25
|
+
left: ASTNode;
|
|
26
|
+
right: ASTNode;
|
|
27
|
+
start: number;
|
|
28
|
+
end: number;
|
|
29
|
+
}
|
|
30
|
+
export interface GroupNode {
|
|
31
|
+
type: 'Group';
|
|
32
|
+
expression: ASTNode;
|
|
33
|
+
boost?: number;
|
|
34
|
+
start: number;
|
|
35
|
+
end: number;
|
|
36
|
+
}
|
|
37
|
+
export interface NotNode {
|
|
38
|
+
type: 'Not';
|
|
39
|
+
expression: ASTNode;
|
|
40
|
+
start: number;
|
|
41
|
+
end: number;
|
|
42
|
+
}
|
|
43
|
+
export interface SavedSearchNode {
|
|
44
|
+
type: 'SavedSearch';
|
|
45
|
+
name: string;
|
|
46
|
+
start: number;
|
|
47
|
+
end: number;
|
|
48
|
+
}
|
|
49
|
+
export interface HistoryRefNode {
|
|
50
|
+
type: 'HistoryRef';
|
|
51
|
+
ref: string;
|
|
52
|
+
start: number;
|
|
53
|
+
end: number;
|
|
54
|
+
}
|
|
55
|
+
export interface BareTermNode {
|
|
56
|
+
type: 'BareTerm';
|
|
57
|
+
value: string;
|
|
58
|
+
quoted: boolean;
|
|
59
|
+
boost?: number;
|
|
60
|
+
fuzzy?: number;
|
|
61
|
+
proximity?: number;
|
|
62
|
+
start: number;
|
|
63
|
+
end: number;
|
|
64
|
+
}
|
|
65
|
+
export interface RegexNode {
|
|
66
|
+
type: 'Regex';
|
|
67
|
+
pattern: string;
|
|
68
|
+
start: number;
|
|
69
|
+
end: number;
|
|
70
|
+
}
|
|
71
|
+
export interface RangeNode {
|
|
72
|
+
type: 'Range';
|
|
73
|
+
field?: string;
|
|
74
|
+
lower: string;
|
|
75
|
+
upper: string;
|
|
76
|
+
lowerInclusive: boolean;
|
|
77
|
+
upperInclusive: boolean;
|
|
78
|
+
lowerQuoted: boolean;
|
|
79
|
+
upperQuoted: boolean;
|
|
80
|
+
/** Character offset of the lower bound value (inclusive). */
|
|
81
|
+
lowerStart: number;
|
|
82
|
+
/** Character offset of the lower bound value (exclusive). */
|
|
83
|
+
lowerEnd: number;
|
|
84
|
+
/** Character offset of the upper bound value (inclusive). */
|
|
85
|
+
upperStart: number;
|
|
86
|
+
/** Character offset of the upper bound value (exclusive). */
|
|
87
|
+
upperEnd: number;
|
|
88
|
+
start: number;
|
|
89
|
+
end: number;
|
|
90
|
+
}
|
|
91
|
+
export interface ErrorNode {
|
|
92
|
+
type: 'Error';
|
|
93
|
+
value: string;
|
|
94
|
+
message: string;
|
|
95
|
+
start: number;
|
|
96
|
+
end: number;
|
|
97
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ColorConfig, StyleConfig } from '../types';
|
|
2
|
+
|
|
3
|
+
type Styles = {
|
|
4
|
+
[key: string]: React.CSSProperties;
|
|
5
|
+
};
|
|
6
|
+
export declare function mergeColors(custom?: ColorConfig): Required<ColorConfig>;
|
|
7
|
+
export declare function mergeStyles(custom?: StyleConfig): Required<StyleConfig>;
|
|
8
|
+
export declare function getInputContainerStyle(colors: Required<ColorConfig>, customStyle?: React.CSSProperties): React.CSSProperties;
|
|
9
|
+
export declare function getEditableStyle(colors: Required<ColorConfig>, styles: Required<StyleConfig>): React.CSSProperties;
|
|
10
|
+
export declare function getEditableFocusStyle(styles: Required<StyleConfig>): React.CSSProperties;
|
|
11
|
+
export declare function getPlaceholderStyle(colors: Required<ColorConfig>, styles: Required<StyleConfig>): React.CSSProperties;
|
|
12
|
+
export declare function getDropdownStyle(colors: Required<ColorConfig>, styles: Required<StyleConfig>): React.CSSProperties;
|
|
13
|
+
export declare function getDropdownItemStyle(isSelected: boolean, colors: Required<ColorConfig>, styles: Required<StyleConfig>): React.CSSProperties;
|
|
14
|
+
export declare function getDropdownItemLabelStyle(isSelected: boolean): React.CSSProperties;
|
|
15
|
+
export declare function getDropdownItemDescStyle(isSelected: boolean): React.CSSProperties;
|
|
16
|
+
export declare function getDropdownItemTypeStyle(isSelected: boolean, styles: Required<StyleConfig>): React.CSSProperties;
|
|
17
|
+
export declare function getSquigglyStyle(left: number, width: number): React.CSSProperties;
|
|
18
|
+
export declare function getDatePickerStyle(colors: Required<ColorConfig>, styles: Required<StyleConfig>): Styles;
|
|
19
|
+
export {};
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
import { ASTNode } from './parser/ast';
|
|
2
|
+
import { CursorContext } from './parser/Parser';
|
|
3
|
+
import { Suggestion } from './autocomplete/suggestionTypes';
|
|
4
|
+
import { ValidationError } from './validation/Validator';
|
|
5
|
+
import * as React from 'react';
|
|
6
|
+
/** Supported field types for search fields. Determines validation rules and autocomplete behavior. */
|
|
7
|
+
export type FieldType = 'string' | 'number' | 'date' | 'boolean' | 'ip';
|
|
8
|
+
/** Structured result from a custom validation callback, allowing explicit severity control. */
|
|
9
|
+
export interface ValidationResult {
|
|
10
|
+
/** Human-readable message. */
|
|
11
|
+
message: string;
|
|
12
|
+
/** `'error'` (default) renders red squiggles; `'warning'` renders amber squiggles. */
|
|
13
|
+
severity: 'error' | 'warning';
|
|
14
|
+
}
|
|
15
|
+
/** Return type for the `validateValue` callback. A plain string is treated as an error. */
|
|
16
|
+
export type ValidateReturn = string | ValidationResult | null;
|
|
17
|
+
/**
|
|
18
|
+
* Context passed to the top-level `validateValue` callback describing the value being validated.
|
|
19
|
+
*/
|
|
20
|
+
export interface ValidateValueContext {
|
|
21
|
+
/** The raw value string being validated. */
|
|
22
|
+
value: string;
|
|
23
|
+
/** Where this value appears in the query. */
|
|
24
|
+
position: 'field_value' | 'range_start' | 'range_end' | 'bare_term' | 'field_group_term';
|
|
25
|
+
/** Field name, if this value is associated with a field (absent for bare terms). */
|
|
26
|
+
fieldName?: string;
|
|
27
|
+
/** Resolved FieldConfig, if this value is associated with a known field. */
|
|
28
|
+
fieldConfig?: FieldConfig;
|
|
29
|
+
/** Whether the value is double-quoted (phrase). */
|
|
30
|
+
quoted: boolean;
|
|
31
|
+
/** Comparison operator if present (e.g. `>`, `>=`, `<`, `<=`). Only for field_value position. */
|
|
32
|
+
operator?: string;
|
|
33
|
+
/** For range bounds: whether the bound is inclusive (`[`/`]`) or exclusive (`{`/`}`). */
|
|
34
|
+
inclusive?: boolean;
|
|
35
|
+
}
|
|
36
|
+
/** Configuration for a searchable field. Defines the field's name, type, and validation behavior. */
|
|
37
|
+
export interface FieldConfig {
|
|
38
|
+
/** Field name used in queries (e.g. `status` in `status:active`). */
|
|
39
|
+
name: string;
|
|
40
|
+
/** Alternative names that resolve to this field. Typing an alias (e.g. `contact_name:value`) behaves identically to using `name`. */
|
|
41
|
+
aliases?: string[];
|
|
42
|
+
/** Human-readable label shown in autocomplete suggestions. Falls back to `name` if omitted. */
|
|
43
|
+
label?: string;
|
|
44
|
+
/** Data type that determines validation and autocomplete behavior. */
|
|
45
|
+
type: FieldType;
|
|
46
|
+
/** Allowed values for `enum` fields, or value hints for other types. Shown in autocomplete. */
|
|
47
|
+
suggestions?: string[];
|
|
48
|
+
/** Allowed comparison operators. Defaults to `>`, `>=`, `<`, `<=` for number/date fields. */
|
|
49
|
+
operators?: string[];
|
|
50
|
+
/** Description shown alongside the field in autocomplete suggestions. */
|
|
51
|
+
description?: string;
|
|
52
|
+
/** Custom placeholder hint shown in the dropdown while typing a value for this field (e.g. "Search by company name..."). Overrides the default type-based hint. Set to `false` to suppress the hint entirely. */
|
|
53
|
+
placeholder?: string | false;
|
|
54
|
+
/** When `true`, the dropdown shows a "Searching..." spinner immediately when entering this field's value (instead of the sync hint). Use for fields whose values are provided by `fetchSuggestions`. @default false */
|
|
55
|
+
asyncSearch?: boolean;
|
|
56
|
+
/** Label shown next to the loading spinner for async fields. Accepts a static string or a callback receiving the current partial text. @default "Searching..." */
|
|
57
|
+
asyncSearchLabel?: string | ((partial: string) => string);
|
|
58
|
+
}
|
|
59
|
+
/** A saved/named search that users can reference with `#name` syntax. */
|
|
60
|
+
export interface SavedSearch {
|
|
61
|
+
/** Unique identifier for the saved search. */
|
|
62
|
+
id: string;
|
|
63
|
+
/** Display name, also used as the `#` trigger (e.g. `#vip-active`). */
|
|
64
|
+
name: string;
|
|
65
|
+
/** The query string this saved search expands to. */
|
|
66
|
+
query: string;
|
|
67
|
+
/** Optional description shown in the autocomplete dropdown. */
|
|
68
|
+
description?: string;
|
|
69
|
+
}
|
|
70
|
+
/** A previous search query that users can reference with `!` syntax. */
|
|
71
|
+
export interface HistoryEntry {
|
|
72
|
+
/** The query string from the history entry. */
|
|
73
|
+
query: string;
|
|
74
|
+
/** Unix timestamp (ms) of when the query was executed. Used for ordering. */
|
|
75
|
+
timestamp?: number;
|
|
76
|
+
/** Optional label for display in the autocomplete dropdown. Falls back to `query`. */
|
|
77
|
+
label?: string;
|
|
78
|
+
}
|
|
79
|
+
/** An item returned by the async `fetchSuggestions` callback for field value autocomplete. */
|
|
80
|
+
export interface SuggestionItem {
|
|
81
|
+
/** The value to insert when this suggestion is accepted. */
|
|
82
|
+
text: string;
|
|
83
|
+
/** Display label in the dropdown. Falls back to `text` if omitted. */
|
|
84
|
+
label?: string;
|
|
85
|
+
/** Additional description shown alongside the suggestion. */
|
|
86
|
+
description?: string;
|
|
87
|
+
/** Category label (e.g. "string", "recent") shown as a badge in the dropdown. */
|
|
88
|
+
type?: string;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Color overrides for syntax highlighting and UI elements.
|
|
92
|
+
* All values are CSS color strings (hex, rgb, etc.). Omitted keys fall back to `DEFAULT_COLORS`.
|
|
93
|
+
*/
|
|
94
|
+
export interface ColorConfig {
|
|
95
|
+
/** Field name in `field:value` pairs (e.g. `status` in `status:active`). */
|
|
96
|
+
fieldName?: string;
|
|
97
|
+
/** Field value in `field:value` pairs (e.g. `active` in `status:active`). */
|
|
98
|
+
fieldValue?: string;
|
|
99
|
+
/** Comparison operators (`>`, `>=`, `<`, `<=`). */
|
|
100
|
+
operator?: string;
|
|
101
|
+
/** Boolean operators (`AND`, `OR`, `NOT`). */
|
|
102
|
+
booleanOp?: string;
|
|
103
|
+
/** Double-quoted phrase values (`"hello world"`). Single quotes are not quote delimiters. */
|
|
104
|
+
quoted?: string;
|
|
105
|
+
/** Parentheses (`(`, `)`). */
|
|
106
|
+
paren?: string;
|
|
107
|
+
/** Saved search references (`#name`). */
|
|
108
|
+
savedSearch?: string;
|
|
109
|
+
/** History references (`!query`). */
|
|
110
|
+
historyRef?: string;
|
|
111
|
+
/** Wildcard characters (`*`, `?`). */
|
|
112
|
+
wildcard?: string;
|
|
113
|
+
/** Validation error underlines and tooltips. */
|
|
114
|
+
error?: string;
|
|
115
|
+
/** Background color for input, dropdown, and tooltips. */
|
|
116
|
+
background?: string;
|
|
117
|
+
/** Default text color. */
|
|
118
|
+
text?: string;
|
|
119
|
+
/** Placeholder text color. */
|
|
120
|
+
placeholder?: string;
|
|
121
|
+
/** Cursor (caret) color. */
|
|
122
|
+
cursor?: string;
|
|
123
|
+
/** Background of the selected dropdown item. */
|
|
124
|
+
dropdownSelected?: string;
|
|
125
|
+
/** Background of hovered dropdown items. */
|
|
126
|
+
dropdownHover?: string;
|
|
127
|
+
/** Regex delimiter slashes (`/`). */
|
|
128
|
+
regexDelimiter?: string;
|
|
129
|
+
/** Regex character classes (`[abc]`, `[^0-9]`). */
|
|
130
|
+
regexCharClass?: string;
|
|
131
|
+
/** Regex group parentheses and non-capturing groups (`(?:`, `(?=`). */
|
|
132
|
+
regexGroup?: string;
|
|
133
|
+
/** Regex escape sequences (`\d`, `\w`, `\.`). */
|
|
134
|
+
regexEscape?: string;
|
|
135
|
+
/** Regex quantifiers (`+`, `*`, `?`, `{n,m}`). */
|
|
136
|
+
regexQuantifier?: string;
|
|
137
|
+
/** Regex anchors (`^`, `$`). */
|
|
138
|
+
regexAnchor?: string;
|
|
139
|
+
/** Regex alternation operator (`|`). */
|
|
140
|
+
regexAlternation?: string;
|
|
141
|
+
/** Regex literal text. */
|
|
142
|
+
regexText?: string;
|
|
143
|
+
/** Background highlight for matched parenthesis pairs. */
|
|
144
|
+
matchedParenBg?: string;
|
|
145
|
+
/** Warning-severity squiggly underlines (e.g. ambiguous precedence). */
|
|
146
|
+
warning?: string;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Structural and layout style overrides for the input and dropdown.
|
|
150
|
+
* All string values are CSS values. Omitted keys fall back to `DEFAULT_STYLES`.
|
|
151
|
+
*/
|
|
152
|
+
export interface StyleConfig {
|
|
153
|
+
/** Shared font family across input, dropdown, and placeholders. */
|
|
154
|
+
fontFamily?: string;
|
|
155
|
+
/** Base font size for the input. */
|
|
156
|
+
fontSize?: string;
|
|
157
|
+
/** Minimum height of the input element. */
|
|
158
|
+
inputMinHeight?: string;
|
|
159
|
+
/** Padding inside the input element. */
|
|
160
|
+
inputPadding?: string;
|
|
161
|
+
/** Border width of the input element. */
|
|
162
|
+
inputBorderWidth?: string;
|
|
163
|
+
/** Border color of the input element (unfocused). */
|
|
164
|
+
inputBorderColor?: string;
|
|
165
|
+
/** Border radius of the input element. */
|
|
166
|
+
inputBorderRadius?: string;
|
|
167
|
+
/** Border color when the input is focused. */
|
|
168
|
+
inputFocusBorderColor?: string;
|
|
169
|
+
/** Box shadow when the input is focused (e.g. focus ring). */
|
|
170
|
+
inputFocusShadow?: string;
|
|
171
|
+
/** Border color of the autocomplete dropdown. */
|
|
172
|
+
dropdownBorderColor?: string;
|
|
173
|
+
/** Border radius of the autocomplete dropdown. */
|
|
174
|
+
dropdownBorderRadius?: string;
|
|
175
|
+
/** Box shadow of the autocomplete dropdown. */
|
|
176
|
+
dropdownShadow?: string;
|
|
177
|
+
/** Maximum height of the dropdown before scrolling. */
|
|
178
|
+
dropdownMaxHeight?: string;
|
|
179
|
+
/** Minimum width of the dropdown. */
|
|
180
|
+
dropdownMinWidth?: string;
|
|
181
|
+
/** Maximum width of the dropdown. */
|
|
182
|
+
dropdownMaxWidth?: string;
|
|
183
|
+
/** CSS z-index for the dropdown and date picker portals. */
|
|
184
|
+
dropdownZIndex?: number;
|
|
185
|
+
/** Padding for each dropdown item. */
|
|
186
|
+
dropdownItemPadding?: string;
|
|
187
|
+
/** Font size for dropdown item text. */
|
|
188
|
+
dropdownItemFontSize?: string;
|
|
189
|
+
/** Background color for type badges (unselected). */
|
|
190
|
+
typeBadgeBg?: string;
|
|
191
|
+
/** Background color for type badges (selected row). */
|
|
192
|
+
typeBadgeSelectedBg?: string;
|
|
193
|
+
/** Text color for type badges (unselected). */
|
|
194
|
+
typeBadgeColor?: string;
|
|
195
|
+
/** Text color for type badges (selected row). */
|
|
196
|
+
typeBadgeSelectedColor?: string;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Configuration for the autocomplete dropdown: when it appears, what it shows, and
|
|
200
|
+
* how suggestion items are rendered. All properties are optional with sensible defaults.
|
|
201
|
+
*/
|
|
202
|
+
export interface DropdownConfig {
|
|
203
|
+
/** Controls when the dropdown appears. `'always'` (default) shows it as you type.
|
|
204
|
+
* `'never'` disables it entirely. `'manual'` requires Ctrl+Space. @default 'always' */
|
|
205
|
+
mode?: 'always' | 'never' | 'manual' | 'input';
|
|
206
|
+
/** When true, the dropdown spans the full input width instead of following the caret. @default false */
|
|
207
|
+
alignToInput?: boolean;
|
|
208
|
+
/** Maximum number of suggestions shown. @default 10 */
|
|
209
|
+
maxSuggestions?: number;
|
|
210
|
+
/** Debounce delay in ms for async `fetchSuggestions` calls. @default 200 */
|
|
211
|
+
suggestDebounceMs?: number;
|
|
212
|
+
/** Show the `#saved-search` hint in the dropdown. @default true */
|
|
213
|
+
showSavedSearchHint?: boolean;
|
|
214
|
+
/** Show the `!history` hint in the dropdown. @default true */
|
|
215
|
+
showHistoryHint?: boolean;
|
|
216
|
+
/** Show boolean operator suggestions (AND, OR, NOT). @default true */
|
|
217
|
+
showOperators?: boolean;
|
|
218
|
+
/** Show dropdown on navigation events (click, arrow keys, focus). When false,
|
|
219
|
+
* the dropdown only appears in response to typing. @default true */
|
|
220
|
+
onNavigation?: boolean;
|
|
221
|
+
/** Delay in ms before the dropdown appears on navigation events. Typing is always
|
|
222
|
+
* immediate. If the user types before the delay elapses, the timer is cancelled.
|
|
223
|
+
* Ignored when `onNavigation` is false. @default 0 */
|
|
224
|
+
navigationDelay?: number;
|
|
225
|
+
/** Custom renderer for field value hints. Return a React element for rich content,
|
|
226
|
+
* or null/undefined for the default hint. */
|
|
227
|
+
renderFieldHint?: (field: FieldConfig, partial: string) => React.ReactNode | null | undefined;
|
|
228
|
+
/** Custom renderer for history suggestion items. Return a React element to replace
|
|
229
|
+
* the default layout, or null/undefined for the default. */
|
|
230
|
+
renderHistoryItem?: (entry: HistoryEntry, isSelected: boolean) => React.ReactNode | null | undefined;
|
|
231
|
+
/** Custom renderer for saved search suggestion items. Return a React element to replace
|
|
232
|
+
* the default layout, or null/undefined for the default. */
|
|
233
|
+
renderSavedSearchItem?: (search: SavedSearch, isSelected: boolean) => React.ReactNode | null | undefined;
|
|
234
|
+
/** Custom renderer for a header above the suggestion list. Return a React element,
|
|
235
|
+
* or null/undefined for no header. */
|
|
236
|
+
renderHeader?: (context: CursorContext) => React.ReactNode | null | undefined;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Feature toggles for optional editing behaviors. All default to false except `multiline`.
|
|
240
|
+
*/
|
|
241
|
+
export interface FeaturesConfig {
|
|
242
|
+
/** Enable multiline input with Shift+Enter for line breaks. @default true */
|
|
243
|
+
multiline?: boolean;
|
|
244
|
+
/** First Ctrl+A selects current token, second selects all. @default false */
|
|
245
|
+
smartSelectAll?: boolean;
|
|
246
|
+
/** Alt+Shift+Arrow expands/shrinks selection through the AST. @default false */
|
|
247
|
+
expandSelection?: boolean;
|
|
248
|
+
/** Pressing `*` with a single value token selected wraps it in wildcards. @default false */
|
|
249
|
+
wildcardWrap?: boolean;
|
|
250
|
+
/** Enable `#name` saved-search syntax and autocomplete. When false, `#` is a regular character. @default false */
|
|
251
|
+
savedSearches?: boolean;
|
|
252
|
+
/** Enable `!query` history-search syntax and autocomplete. When false, `!` is a regular character. @default false */
|
|
253
|
+
historySearch?: boolean;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Imperative API handle for the ElasticInput component.
|
|
257
|
+
* Obtained via the `inputRef` callback prop.
|
|
258
|
+
*/
|
|
259
|
+
export interface ElasticInputAPI {
|
|
260
|
+
/** Returns the current raw query string. */
|
|
261
|
+
getValue: () => string;
|
|
262
|
+
/** Programmatically sets the input value. Triggers re-lex, re-parse, and re-validate. */
|
|
263
|
+
setValue: (value: string) => void;
|
|
264
|
+
/** Focuses the input element. */
|
|
265
|
+
focus: () => void;
|
|
266
|
+
/** Blurs the input element. */
|
|
267
|
+
blur: () => void;
|
|
268
|
+
/** Returns the current parsed AST, or `null` if the input is empty. */
|
|
269
|
+
getAST: () => ASTNode | null;
|
|
270
|
+
/** Returns the current validation errors (including syntax errors). */
|
|
271
|
+
getValidationErrors: () => ValidationError[];
|
|
272
|
+
/** Selects a character range in the input. Focuses the input if not already focused. */
|
|
273
|
+
setSelection: (start: number, end: number) => void;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Props for the ElasticInput component.
|
|
277
|
+
*
|
|
278
|
+
* @example
|
|
279
|
+
* ```tsx
|
|
280
|
+
* <ElasticInput
|
|
281
|
+
* fields={[
|
|
282
|
+
* { name: 'status', type: 'string', suggestions: ['active', 'inactive'] },
|
|
283
|
+
* { name: 'price', type: 'number' },
|
|
284
|
+
* ]}
|
|
285
|
+
* onSearch={(query, ast) => console.log('Search:', query)}
|
|
286
|
+
* placeholder="Search..."
|
|
287
|
+
* />
|
|
288
|
+
* ```
|
|
289
|
+
*/
|
|
290
|
+
/** Context passed to the `onTab` callback. */
|
|
291
|
+
export interface TabContext {
|
|
292
|
+
/** The currently selected suggestion, or `null` if nothing is highlighted. */
|
|
293
|
+
suggestion: Suggestion | null;
|
|
294
|
+
/** Current cursor context (what the user is typing). */
|
|
295
|
+
cursorContext: CursorContext;
|
|
296
|
+
/** The current raw query string. */
|
|
297
|
+
query: string;
|
|
298
|
+
}
|
|
299
|
+
/** Return type for the `onTab` callback. Each action defaults to `false` when omitted. */
|
|
300
|
+
export interface TabActionResult {
|
|
301
|
+
/** Accept the currently selected suggestion (if any). */
|
|
302
|
+
accept?: boolean;
|
|
303
|
+
/** Move focus out of the input. */
|
|
304
|
+
blur?: boolean;
|
|
305
|
+
/** Trigger `onSearch` with the current (post-accept) query. */
|
|
306
|
+
submit?: boolean;
|
|
307
|
+
}
|
|
308
|
+
/** Field definitions — either a static array or an async loader function. */
|
|
309
|
+
export type FieldsSource = FieldConfig[] | (() => Promise<FieldConfig[]>);
|
|
310
|
+
export interface ElasticInputProps {
|
|
311
|
+
/** Field definitions that determine autocomplete, validation, and syntax highlighting. Accepts a static array or an async loader function. */
|
|
312
|
+
fields: FieldsSource;
|
|
313
|
+
/** Called when the user submits a search (Enter on a value, or Ctrl+Enter). */
|
|
314
|
+
onSearch?: (query: string, ast: ASTNode | null) => void;
|
|
315
|
+
/** Called on every input change with the current query and AST. */
|
|
316
|
+
onChange?: (query: string, ast: ASTNode | null) => void;
|
|
317
|
+
/** Called when validation errors change. Useful for external error display. */
|
|
318
|
+
onValidationChange?: (errors: ValidationError[]) => void;
|
|
319
|
+
/** Controlled value. When provided, the component reflects this value. */
|
|
320
|
+
value?: string;
|
|
321
|
+
/** Initial value for uncontrolled usage. Ignored if `value` is provided. */
|
|
322
|
+
defaultValue?: string;
|
|
323
|
+
/** Saved searches available via `#name` syntax. Can be an array or async loader. */
|
|
324
|
+
savedSearches?: SavedSearch[] | (() => Promise<SavedSearch[]>);
|
|
325
|
+
/** Search history available via `!` syntax. Can be an array or async loader. */
|
|
326
|
+
searchHistory?: HistoryEntry[] | (() => Promise<HistoryEntry[]>);
|
|
327
|
+
/** Async callback for fetching field value suggestions. Called with field name and partial text. */
|
|
328
|
+
fetchSuggestions?: (fieldName: string, partial: string) => Promise<SuggestionItem[]>;
|
|
329
|
+
/** Color overrides for syntax highlighting and UI elements. Merged with `DEFAULT_COLORS`. */
|
|
330
|
+
colors?: ColorConfig;
|
|
331
|
+
/** Style overrides for input and dropdown layout. Merged with `DEFAULT_STYLES`. */
|
|
332
|
+
styles?: StyleConfig;
|
|
333
|
+
/** Placeholder text shown when the input is empty and unfocused. */
|
|
334
|
+
placeholder?: string;
|
|
335
|
+
/** CSS class name applied to the outer container `<div>`. */
|
|
336
|
+
className?: string;
|
|
337
|
+
/** Inline styles applied to the outer container `<div>`. */
|
|
338
|
+
style?: React.CSSProperties;
|
|
339
|
+
/** Dropdown behavior, rendering, and appearance configuration. */
|
|
340
|
+
dropdown?: DropdownConfig;
|
|
341
|
+
/** Feature toggles for optional editing behaviors. */
|
|
342
|
+
features?: FeaturesConfig;
|
|
343
|
+
/** Callback that receives the imperative API handle for programmatic control. */
|
|
344
|
+
inputRef?: (api: ElasticInputAPI) => void;
|
|
345
|
+
/** Custom presets for the date range picker. When provided, completely replaces the built-in presets (Today, Last 7 days, etc.). Pass `[]` to hide presets entirely. Only shown in range mode. */
|
|
346
|
+
datePresets?: {
|
|
347
|
+
label: string;
|
|
348
|
+
value: string;
|
|
349
|
+
}[];
|
|
350
|
+
/** Called on keydown events before internal handling. If `e.preventDefault()` is called, internal keyboard handling is skipped. */
|
|
351
|
+
onKeyDown?: (e: React.KeyboardEvent<HTMLDivElement>) => void;
|
|
352
|
+
/** Called when the input gains focus. */
|
|
353
|
+
onFocus?: () => void;
|
|
354
|
+
/** Called when the input loses focus. */
|
|
355
|
+
onBlur?: () => void;
|
|
356
|
+
/**
|
|
357
|
+
* Override Tab key behavior. Called when Tab is pressed, with the current suggestion (if any),
|
|
358
|
+
* cursor context, and query string. Return an object specifying which actions to perform.
|
|
359
|
+
* Each action defaults to `false` when omitted.
|
|
360
|
+
*
|
|
361
|
+
* - `accept`: Accept the currently selected suggestion (if any).
|
|
362
|
+
* - `blur`: Move focus out of the input.
|
|
363
|
+
* - `submit`: Trigger `onSearch` with the current query.
|
|
364
|
+
*
|
|
365
|
+
* If this prop is not provided, default behavior applies (accept suggestion if selected,
|
|
366
|
+
* otherwise browser-default tab-out).
|
|
367
|
+
*
|
|
368
|
+
* @example
|
|
369
|
+
* ```tsx
|
|
370
|
+
* onTab={({ suggestion }) => ({
|
|
371
|
+
* accept: !!suggestion,
|
|
372
|
+
* blur: true,
|
|
373
|
+
* })}
|
|
374
|
+
* ```
|
|
375
|
+
*/
|
|
376
|
+
onTab?: (context: TabContext) => TabActionResult;
|
|
377
|
+
/**
|
|
378
|
+
* Top-level custom validation callback. Called for every value in the query (field values,
|
|
379
|
+
* range bounds, bare terms, field group terms). Return an error string (treated as error
|
|
380
|
+
* severity), a `{ message, severity }` object, or `null` if valid.
|
|
381
|
+
*/
|
|
382
|
+
validateValue?: (context: ValidateValueContext) => ValidateReturn;
|
|
383
|
+
}
|