@aquera/nile-visualization 2.9.1 → 2.9.3

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.
Files changed (28) hide show
  1. package/dist/src/nile-chart/nile-chart.css.js +6 -0
  2. package/dist/src/nile-filter-chart/nile-filter-chart.css.js +274 -4
  3. package/dist/src/nile-filter-chart/nile-filter-chart.d.ts +59 -206
  4. package/dist/src/nile-filter-chart/nile-filter-chart.js +330 -436
  5. package/dist/src/nile-filter-chart/utils/badge.d.ts +3 -0
  6. package/dist/src/nile-filter-chart/utils/badge.js +33 -0
  7. package/dist/src/nile-filter-chart/utils/comparison.d.ts +3 -0
  8. package/dist/src/nile-filter-chart/utils/comparison.js +24 -0
  9. package/dist/src/nile-filter-chart/utils/dropdown.d.ts +3 -0
  10. package/dist/src/nile-filter-chart/utils/dropdown.js +24 -0
  11. package/dist/src/nile-filter-chart/utils/preset.d.ts +3 -0
  12. package/dist/src/nile-filter-chart/utils/preset.js +16 -0
  13. package/dist/src/nile-filter-chart/utils/prompt.d.ts +12 -0
  14. package/dist/src/nile-filter-chart/utils/prompt.js +676 -0
  15. package/dist/src/nile-filter-chart/utils/radio.d.ts +3 -0
  16. package/dist/src/nile-filter-chart/utils/radio.js +13 -0
  17. package/dist/src/nile-filter-chart/utils/search.d.ts +3 -0
  18. package/dist/src/nile-filter-chart/utils/search.js +12 -0
  19. package/dist/src/nile-filter-chart/utils/segmented.d.ts +3 -0
  20. package/dist/src/nile-filter-chart/utils/segmented.js +15 -0
  21. package/dist/src/nile-filter-chart/utils/threshold.d.ts +3 -0
  22. package/dist/src/nile-filter-chart/utils/threshold.js +58 -0
  23. package/dist/src/nile-filter-chart/utils/toggle.d.ts +3 -0
  24. package/dist/src/nile-filter-chart/utils/toggle.js +19 -0
  25. package/dist/src/nile-filter-chart/utils/types.d.ts +334 -0
  26. package/dist/src/nile-filter-chart/utils/types.js +2 -0
  27. package/dist/src/nile-kpi-chart/nile-kpi-chart.css.js +62 -4
  28. package/package.json +1 -1
@@ -194,6 +194,12 @@ export const styles = css `
194
194
  contain: none;
195
195
  }
196
196
 
197
+
198
+ .nile-chart-inner--filter {
199
+ overflow: visible;
200
+ contain: none;
201
+ }
202
+
197
203
  /* ── Default slot (custom chart body only — not named slots) ── */
198
204
  slot:not([name])::slotted(*) {
199
205
  display: block;
@@ -382,26 +382,112 @@ export const styles = css `
382
382
  box-shadow: 0 6px 6px -6px rgba(59, 130, 246, 0.45);
383
383
  }
384
384
 
385
-
385
+
386
386
  .fc-prompt:focus-within {
387
387
  box-shadow: 0 8px 8px -6px rgba(59, 130, 246, 0.6);
388
388
  }
389
389
 
390
+ .fc-prompt--no-ai-border {
391
+ padding: 0;
392
+ background: transparent;
393
+ animation: none;
394
+ box-shadow: none;
395
+ }
396
+
397
+ .fc-prompt--no-ai-border:focus-within {
398
+ box-shadow: none;
399
+ }
400
+
401
+ .fc-prompt--no-ai-border .fc-prompt__inner {
402
+ border: 1px solid var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));
403
+ }
404
+
405
+ /* ── Error state ─── */
406
+ /* Drop the animated AI gradient and the 2px outer ring; the error reads
407
+ as a thin red border directly on the input with a soft focus halo,
408
+ and a quiet inline message underneath — no heavy box. */
409
+ .fc-prompt--error {
410
+ padding: 0;
411
+ background: transparent;
412
+ animation: none;
413
+ box-shadow: none;
414
+ }
415
+
416
+ .fc-prompt--error:focus-within {
417
+ box-shadow: none;
418
+ }
419
+
420
+ .fc-prompt--error .fc-prompt__inner {
421
+ background: var(--nile-colors-white-base, var(--ng-colors-bg-primary, #fff));
422
+ border: 1.5px solid var(--nile-colors-error-500, var(--ng-colors-border-error, #f04438));
423
+ transition: border-color 0.15s ease, box-shadow 0.15s ease;
424
+ }
425
+
426
+ .fc-prompt--error:focus-within .fc-prompt__inner {
427
+ border-color: var(--nile-colors-error-600, var(--ng-colors-border-error-strong, #d92d20));
428
+ box-shadow: 0 0 0 4px rgba(240, 68, 56, 0.14);
429
+ }
430
+
431
+ .fc-prompt__error {
432
+ display: flex;
433
+ align-items: center;
434
+ gap: var(--nile-spacing-6px, var(--ng-spacing-1-5));
435
+ margin-top: var(--nile-spacing-6px, var(--ng-spacing-1-5));
436
+ padding: 0 var(--nile-spacing-2px, var(--ng-spacing-0-5));
437
+ color: var(--nile-colors-error-600, var(--ng-colors-text-error-primary-600, #d92d20));
438
+ font-size: var(--nile-type-scale-2, var(--ng-font-size-text-xs));
439
+ line-height: 1.4;
440
+ animation: fc-prompt-error-in 0.18s ease-out both;
441
+ }
442
+
443
+ .fc-prompt__error-icon {
444
+ display: inline-flex;
445
+ align-items: center;
446
+ justify-content: center;
447
+ width: 14px;
448
+ height: 14px;
449
+ border-radius: 50%;
450
+ background: var(--nile-colors-error-500, var(--ng-colors-bg-error-solid, #f04438));
451
+ color: var(--nile-colors-white-base, var(--ng-color-base-white));
452
+ font-weight: var(--nile-font-weight-bold, var(--ng-font-weight-700));
453
+ font-size: 10px;
454
+ line-height: 1;
455
+ flex-shrink: 0;
456
+ }
457
+
458
+ .fc-prompt__error-msg {
459
+ flex: 1;
460
+ word-break: break-word;
461
+ }
462
+
463
+ @keyframes fc-prompt-error-in {
464
+ from { opacity: 0; transform: translateY(-2px); }
465
+ to { opacity: 1; transform: translateY(0); }
466
+ }
467
+
468
+ @media (prefers-reduced-motion: reduce) {
469
+ .fc-prompt__error { animation: none; }
470
+ }
471
+
390
472
  .fc-prompt__inner {
391
473
  position: relative;
392
- display: block;
474
+ display: flex;
475
+ align-items: center;
476
+ gap: var(--nile-spacing-md, var(--ng-spacing-2));
477
+ padding-right: var(--nile-spacing-md, var(--ng-spacing-2));
393
478
  border-radius: var(--nile-radius-radius-xl, var(--ng-radius-md));
394
479
  background: var(--nile-colors-white-base, var(--ng-colors-bg-primary));
395
480
  }
396
481
 
397
482
  .fc-prompt__input {
398
483
  display: block;
399
- width: 100%;
484
+ flex: 1;
485
+ min-width: 0;
400
486
  border: 0;
401
487
  outline: none;
402
488
  background: transparent;
403
489
  border-radius: inherit;
404
- padding: var(--nile-spacing-md, var(--ng-spacing-md)) var(--nile-spacing-lg, var(--ng-spacing-lg));
490
+ padding: var(--nile-spacing-2xl, var(--ng-spacing-5)) var(--nile-spacing-xl, var(--ng-spacing-4));
405
491
  font-family: var(--nile-font-family-serif, var(--ng-font-family-body));
406
492
  font-size: var(--nile-type-scale-4, var(--ng-font-size-text-md));
407
493
  color: var(--nile-colors-dark-900, var(--ng-colors-text-primary-900));
@@ -409,6 +495,190 @@ export const styles = css `
409
495
  box-sizing: border-box;
410
496
  }
411
497
 
498
+ /* ── Mode toggle (Basic / NQL) ─── */
499
+ /* Uses <nile-button-toggle-group>; pin to the right of the input and
500
+ shrink the inner segments via the exposed "base" part so the toggle
501
+ doesn't dominate the prompt height. */
502
+ .fc-prompt__mode {
503
+ flex-shrink: 0;
504
+ align-self: center;
505
+ margin-left: var(--nile-spacing-md, var(--ng-spacing-2));
506
+ border-radius: var(--nile-radius-radius-lg, var(--ng-radius-lg));
507
+ overflow: hidden;
508
+ }
509
+
510
+ .fc-prompt__mode nile-button-toggle::part(base) {
511
+ height: 32px;
512
+ padding: 0 var(--nile-spacing-xl, var(--ng-spacing-4));
513
+ font-size: var(--nile-type-scale-3, var(--ng-font-size-text-sm));
514
+ letter-spacing: 0.03em;
515
+ gap: var(--nile-spacing-6px, var(--ng-spacing-1-5));
516
+ }
517
+
518
+ .fc-prompt__mode-icon {
519
+ display: inline-flex;
520
+ align-items: center;
521
+ line-height: 0;
522
+ }
523
+
524
+ /* ── Row layout: prompt input + mode toggle ─── */
525
+ .fc-prompt-row {
526
+ display: flex;
527
+ align-items: stretch;
528
+ gap: var(--nile-spacing-md, var(--ng-spacing-2));
529
+ width: 100%;
530
+ }
531
+
532
+ .fc-prompt-row .fc-prompt--row-input {
533
+ flex: 1;
534
+ min-width: 0;
535
+ }
536
+
537
+ .fc-prompt__mode nile-button-toggle:first-of-type::part(base) {
538
+ border-top-left-radius: var(--nile-radius-radius-lg, var(--ng-radius-lg));
539
+ border-bottom-left-radius: var(--nile-radius-radius-lg, var(--ng-radius-lg));
540
+ }
541
+
542
+ .fc-prompt__mode nile-button-toggle:last-of-type::part(base) {
543
+ border-top-right-radius: var(--nile-radius-radius-lg, var(--ng-radius-lg));
544
+ border-bottom-right-radius: var(--nile-radius-radius-lg, var(--ng-radius-lg));
545
+ }
546
+
547
+ /* ── Field wrapper + syntax-highlight overlay ─── */
548
+ /* The wrapper holds two layered elements: */
549
+ /* 1) .fc-prompt__highlight — paints the typed text in coloured spans.*/
550
+ /* 2) .fc-prompt__input — transparent text, visible caret, takes */
551
+ /* keyboard input. */
552
+ /* Both elements share the SAME font + padding + line-height so token */
553
+ /* positions align exactly. The overlay is non-interactive. */
554
+ .fc-prompt__field {
555
+ position: relative;
556
+ flex: 1;
557
+ min-width: 0;
558
+ display: block;
559
+ }
560
+ .fc-prompt__field--highlight .fc-prompt__highlight,
561
+ .fc-prompt__field--highlight .fc-prompt__input {
562
+ box-sizing: border-box;
563
+ padding: var(--nile-spacing-md, var(--ng-spacing-2)) var(--nile-spacing-xl, var(--ng-spacing-4));
564
+ font-family: var(--nile-font-family-serif, var(--ng-font-family-body));
565
+ font-size: var(--nile-type-scale-4, var(--ng-font-size-text-md));
566
+ font-weight: 400;
567
+ line-height: 1.4;
568
+ letter-spacing: normal;
569
+ white-space: pre;
570
+ }
571
+
572
+ .fc-prompt__highlight {
573
+ position: absolute;
574
+ inset: 0;
575
+ pointer-events: none;
576
+ color: var(--nile-colors-dark-900, var(--ng-colors-text-primary-900));
577
+ /* overflow-x: auto (not hidden) so JS can sync scrollLeft to the input's
578
+ native horizontal scroll. Without it, white-space: pre content spills
579
+ past the field's right edge and visually overlaps the mode toggle.
580
+ Scrollbar is suppressed since the overlay is non-interactive (only the
581
+ input below it scrolls via keyboard). */
582
+ overflow-x: auto;
583
+ overflow-y: hidden;
584
+ scrollbar-width: none; /* Firefox */
585
+ }
586
+ .fc-prompt__highlight::-webkit-scrollbar { display: none; } /* Chrome / Safari */
587
+
588
+ .fc-prompt__input {
589
+ position: relative;
590
+ display: block;
591
+ width: 100%;
592
+ border: 0;
593
+ outline: none;
594
+ background: transparent;
595
+ color: var(--nile-colors-dark-900, var(--ng-colors-text-primary-900));
596
+ caret-color: var(--nile-colors-dark-900, var(--ng-colors-text-primary-900));
597
+ }
598
+
599
+ /* When the syntax-highlight overlay is on (filtrex modes only) the input
600
+ itself is transparent — only the overlay paints the typed text. */
601
+ .fc-prompt__field--highlight .fc-prompt__input {
602
+ color: transparent;
603
+ }
604
+
605
+ /* ── Custom suggestion dropdown ─── */
606
+ /* Hidden by default; shown only when fc-prompt__inner has focus-within.*/
607
+ /* Mousedown on a suggestion preventDefaults to keep input focus, so */
608
+ /* the dropdown stays open across picks. Click outside → focus-within */
609
+ /* fails → dropdown hides. */
610
+ .fc-prompt__suggestions {
611
+ display: none;
612
+ position: absolute;
613
+ top: calc(100% + 6px);
614
+ left: 0;
615
+ right: 0;
616
+ z-index: 20;
617
+ flex-direction: column;
618
+ max-height: 280px;
619
+ overflow-y: auto;
620
+ background: var(--nile-colors-white-base, var(--ng-colors-bg-primary));
621
+ border: 1px solid var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));
622
+ border-radius: var(--nile-radius-md, var(--ng-radius-md));
623
+ box-shadow: 0 12px 24px -8px rgba(16, 24, 40, 0.12),
624
+ 0 4px 8px -2px rgba(16, 24, 40, 0.06);
625
+ padding: var(--nile-spacing-4px, var(--ng-spacing-1));
626
+ }
627
+
628
+ .fc-prompt__inner:focus-within .fc-prompt__suggestions {
629
+ display: flex;
630
+ }
631
+
632
+ .fc-prompt__suggestion {
633
+ display: flex;
634
+ align-items: center;
635
+ justify-content: space-between;
636
+ gap: var(--nile-spacing-md, var(--ng-spacing-2));
637
+ width: 100%;
638
+ padding: var(--nile-spacing-8px, var(--ng-spacing-2)) var(--nile-spacing-md, var(--ng-spacing-2));
639
+ border: 0;
640
+ border-radius: var(--nile-radius-sm, var(--ng-radius-sm));
641
+ background: transparent;
642
+ font-family: var(--nile-font-family-serif, var(--ng-font-family-body));
643
+ font-size: var(--nile-type-scale-3, var(--ng-font-size-text-sm));
644
+ font-weight: var(--nile-font-weight-medium, var(--ng-font-weight-500));
645
+ color: var(--nile-colors-dark-900, var(--ng-colors-text-primary-900));
646
+ cursor: pointer;
647
+ text-align: left;
648
+ transition: background 0.1s ease;
649
+ }
650
+
651
+ .fc-prompt__suggestion:hover {
652
+ background: var(--nile-colors-neutral-100, var(--ng-colors-bg-secondary));
653
+ }
654
+ /* Keyboard-highlighted state — distinct from hover via brand-tinted bg
655
+ and a left accent bar so it's obvious which row Enter will select. */
656
+ .fc-prompt__suggestion--active,
657
+ .fc-prompt__suggestion--active:hover {
658
+ background: var(--nile-colors-blue-50, var(--ng-colors-bg-brand-secondary, #eff6ff));
659
+ box-shadow: inset 3px 0 0 var(--nile-colors-blue-500, var(--ng-colors-bg-brand-solid, #3b82f6));
660
+ }
661
+
662
+ .fc-prompt__suggestion-label {
663
+ flex: 1;
664
+ min-width: 0;
665
+ overflow: hidden;
666
+ text-overflow: ellipsis;
667
+ white-space: nowrap;
668
+ }
669
+
670
+ .fc-prompt__suggestion-tag {
671
+ flex-shrink: 0;
672
+ padding: 1px 8px;
673
+ border-radius: var(--nile-radius-full, var(--ng-radius-full));
674
+ background: var(--nile-colors-neutral-100, var(--ng-colors-bg-secondary));
675
+ color: var(--nile-colors-neutral-700, var(--ng-colors-text-quaternary-500));
676
+ font-size: 10px;
677
+ font-weight: 600;
678
+ text-transform: uppercase;
679
+ letter-spacing: 0.04em;
680
+ }
681
+
412
682
  .fc-prompt__input::placeholder {
413
683
  color: var(--nile-colors-neutral-700, var(--ng-colors-text-secondary-700));
414
684
  opacity: 0.85;
@@ -1,228 +1,81 @@
1
1
  import { CSSResultArray, TemplateResult } from 'lit';
2
2
  import NileElement from '../internal/nile-element.js';
3
- export type NileTagVariant = 'primary' | 'success' | 'normal' | 'warning' | 'error' | 'info';
4
- export interface FilterOption {
5
- label: string;
6
- value: string;
7
- /** Optional color dot (CSS color string). */
8
- color?: string;
9
- /** Optional nile-tag semantic variant — uses ng tokens directly (preferred over color). */
10
- ngVariant?: NileTagVariant;
11
- /** Optional icon name for preset variant. */
12
- icon?: string;
13
- }
14
- export interface TreeNode {
15
- label: string;
16
- value: string;
17
- expanded?: boolean;
18
- children?: TreeNode[];
19
- }
20
- export interface QueryLanguageConfig {
21
- /** Enables the query layer at all. Default: false. */
22
- enabled: boolean;
23
- /**
24
- * - `'auto'` → submit emits the raw typed string.
25
- * - `'strict'` → submit parses the input with filtrex and emits a
26
- * pure-JSON payload (`{ source }`) plus a sibling
27
- * `evaluate` function on the event detail. On
28
- * parse failure, `nile-prompt-parse-error` fires and
29
- * `nile-prompt-submit` does NOT fire.
30
- * Default: `'auto'`.
31
- */
32
- mode?: 'auto' | 'strict';
33
- /** Parser engine. Currently only `'filtrex'` is supported. */
34
- engine?: 'filtrex';
35
- /** Optional hint text shown beneath the input describing the syntax. */
36
- syntaxHint?: string;
37
- /**
38
- * Extra functions registered with filtrex on top of the built-in set.
39
- * Each function receives the resolved argument values from the
40
- * expression and returns a value usable in further comparisons.
41
- *
42
- * Example: `{ daysAgo: (d) => (Date.now() - +new Date(d)) / 86400000 }`
43
- * Used in expressions like `daysAgo(lastSeen) < 7`.
44
- */
45
- extraFunctions?: Record<string, (...args: any[]) => unknown>;
46
- /**
47
- * Optional value-getter for accessing row properties. Filtrex calls
48
- * this for every identifier reference. Default: dotted property
49
- * access (`row.foo.bar` works out of the box).
50
- *
51
- * Override when your data model uses a Map / class / proxy that
52
- * standard property access can't read.
53
- */
54
- customProp?: (name: string, get: (key: string) => unknown, obj: unknown) => unknown;
55
- }
56
- /**
57
- * Recursive ESTree-shaped node returned by the AST parser. The shape
58
- * matches what `jsep` produces — a small, well-known JS-expression AST.
59
- * Pure JSON: every field is a string, number, boolean, null, or another
60
- * `QueryNode`, so `JSON.stringify` round-trips cleanly.
61
- */
62
- export type QueryNode = {
63
- type: 'Identifier';
64
- name: string;
65
- } | {
66
- type: 'Literal';
67
- value: string | number | boolean | null;
68
- raw?: string;
69
- } | {
70
- type: 'BinaryExpression';
71
- operator: string;
72
- left: QueryNode;
73
- right: QueryNode;
74
- } | {
75
- type: 'LogicalExpression';
76
- operator: string;
77
- left: QueryNode;
78
- right: QueryNode;
79
- } | {
80
- type: 'UnaryExpression';
81
- operator: string;
82
- argument: QueryNode;
83
- prefix: boolean;
84
- } | {
85
- type: 'CallExpression';
86
- callee: QueryNode;
87
- arguments: QueryNode[];
88
- } | {
89
- type: 'MemberExpression';
90
- computed: boolean;
91
- object: QueryNode;
92
- property: QueryNode;
93
- } | {
94
- type: 'ArrayExpression';
95
- elements: QueryNode[];
96
- } | {
97
- type: 'Compound';
98
- body: QueryNode[];
99
- };
100
- export type QueryJson = {
101
- /** The exact string the user typed, retained for display / serialization. */
102
- source: string;
103
- ast: QueryNode;
104
- };
105
- export type QuerySubmitDetail = {
106
- id: string;
107
- /** JSON-serializable payload — string in auto mode, `QueryJson` in strict. */
108
- value: string | QueryJson;
109
- /** Compiled filtrex predicate. Only present in strict mode on success.
110
- * Use as `data.filter(e.detail.evaluate)`. */
111
- evaluate?: (row: unknown) => unknown;
112
- };
113
- export interface FilterControl {
114
- id: string;
115
- label: string;
116
- /** Optional subtitle shown below the label. */
117
- description?: string;
118
- selection: 'single' | 'multi';
119
- variant: 'badge' | 'dropdown' | 'segmented' | 'radio' | 'toggle' | 'slider' | 'search' | 'comparison' | 'threshold' | 'tree' | 'preset' | 'prompt';
120
- options?: FilterOption[];
121
- value?: string | string[] | number[] | boolean;
122
- min?: number;
123
- max?: number;
124
- step?: number;
125
- prefix?: string;
126
- suffix?: string;
127
- placeholder?: string;
128
- placeholders?: string[];
129
- /** Typewriter speed in ms per character (default 60). */
130
- typeSpeedMs?: number;
131
- /** Pause before deleting a typed phrase (default 1400). */
132
- pauseBeforeDeleteMs?: number;
133
- /** Pause between phrases after deletion (default 400). */
134
- pauseBetweenMs?: number;
135
- /**
136
- * Prompt variant only. Inline callback invoked on every keystroke with
137
- * the current value of the input (the typed string) and the control id.
138
- * Called *in addition to* the `nile-prompt-input` event — use whichever
139
- * suits the consumer's wiring style.
140
- */
141
- onType?: (value: string, id: string) => void;
142
- /**
143
- * Prompt variant only. Inline callback invoked when the user presses
144
- * Enter inside the prompt input. Called in addition to the
145
- * `nile-prompt-submit` event.
146
- *
147
- * - auto mode (default) → `value` is the raw `string` the user typed.
148
- * - strict mode (success) → `value` is a `QueryJson` (pure-JSON
149
- * `{ source }`); the compiled predicate is
150
- * passed as the third argument so callers
151
- * that want to filter inline can. JSON
152
- * consumers can ignore that argument.
153
- * - strict mode (parse fail) → routes through `onParseError` instead;
154
- * `onSubmit` is NOT called.
155
- */
156
- onSubmit?: (value: string | QueryJson, id: string, evaluate?: (row: unknown) => unknown) => void;
157
- /**
158
- * Prompt variant only. Inline callback invoked when `queryLanguage.mode`
159
- * is `'strict'` and the user-typed expression FAILS to parse on submit.
160
- * Mirrors the `nile-prompt-parse-error` event.
161
- */
162
- onParseError?: (input: string, error: Error, id: string) => void;
163
- queryLanguage?: QueryLanguageConfig;
164
- gradientColors?: string[];
165
- gradientDirection?: string;
166
- gradientSpeedMs?: number;
167
- valueB?: string;
168
- operator?: string;
169
- thresholdValue?: number | string;
170
- treeData?: TreeNode[];
171
- }
172
- export interface FilterGroup {
173
- type: 'group';
174
- label: string;
175
- description?: string;
176
- collapsible?: boolean;
177
- controls: FilterControl[];
178
- }
179
- export type FilterEntry = FilterControl | FilterGroup;
180
- export type FilterChartConfig = {
181
- type: 'filter';
182
- controls: FilterEntry[];
183
- [key: string]: unknown;
184
- };
185
- export type FilterChartSeparatedPayload = {
186
- chart: FilterChartConfig;
187
- aq?: Record<string, unknown>;
188
- };
189
- export declare class NileFilterChart extends NileElement {
3
+ import type { FilterChartHost, FilterChartSeparatedPayload, NormalizedFilterControl, PromptMode } from './utils/types.js';
4
+ export type { NileTagVariant, FilterOption, QueryLanguageConfig, QueryNode, QueryJson, FilterChangeDetail, FilterControl, FilterGroup, FilterEntry, FilterChartConfig, FilterChartSeparatedPayload, PromptMode, } from './utils/types.js';
5
+ export declare class NileFilterChart extends NileElement implements FilterChartHost {
190
6
  static get styles(): CSSResultArray;
191
7
  config: FilterChartSeparatedPayload | null;
192
- private selectedValues;
8
+ selectedValues: Map<string, unknown>;
193
9
  private collapsedGroups;
194
10
  /** Currently displayed (animated) placeholder text per prompt-variant control id. */
195
- private _promptPlaceholder;
11
+ promptPlaceholder: Map<string, string>;
12
+ /** Validation messages per prompt control id (strict-mode parse failures). */
13
+ promptErrors: Map<string, string>;
14
+ /** Runtime mode per prompt control id. Only populated for controls with `queryLanguage.enabled`. */
15
+ promptModes: Map<string, PromptMode>;
16
+ /** Highlighted suggestion index per prompt control id (-1 = none highlighted). */
17
+ promptActiveIndex: Map<string, number>;
196
18
  /** Active typewriter timers per prompt control id (so we can stop them). */
197
19
  private _promptTimers;
20
+ /** Compiled filtrex predicates per prompt control id (strict-mode successes). */
21
+ private _promptEvaluators;
22
+ /** Parsed AST per prompt control id (strict-mode successes). */
23
+ private _promptAsts;
24
+ /** Monotonic per-control token used to ignore stale async validations. */
25
+ private _validationTokens;
26
+ /** Pending debounce timers for prompt input — gates validation + nile-change emission. */
27
+ private _promptDebounce;
28
+ /** Pause after the last keystroke before validating and emitting nile-change. */
29
+ private static readonly _PROMPT_DEBOUNCE_MS;
198
30
  connectedCallback(): void;
199
31
  disconnectedCallback(): void;
200
32
  updated(changed: Map<string, unknown>): void;
33
+ setValue(id: string, value: unknown): void;
34
+ /**
35
+ * Update a prompt control's value. The value lands in `selectedValues`
36
+ * immediately so the input stays responsive, but validation, error
37
+ * rendering, and the `nile-change` event are debounced — they only
38
+ * fire after `_PROMPT_DEBOUNCE_MS` of keyboard quiet.
39
+ */
40
+ handlePromptInput(ctrl: NormalizedFilterControl, value: string): void;
41
+ /**
42
+ * Switch the runtime mode for a prompt control. Leaving NQL clears
43
+ * validation; entering NQL re-validates the current value. The mode
44
+ * toggle is an explicit user action, so any pending typing debounce
45
+ * is cancelled and the change applies immediately (regardless of
46
+ * `validateOn`).
47
+ */
48
+ setPromptMode(ctrl: NormalizedFilterControl, mode: PromptMode): void;
49
+ /**
50
+ * Force-validate a prompt's current value. Used by `validateOn: 'submit'`
51
+ * on Enter — bypasses the debounce and runs validation right away.
52
+ */
53
+ submitPrompt(ctrl: NormalizedFilterControl): void;
54
+ setPromptActiveIndex(id: string, idx: number): void;
55
+ private _validateOrClear;
56
+ private _clearPromptValidation;
201
57
  private _syncPromptAnimations;
202
58
  private _startPromptAnimation;
203
59
  private _stopPromptAnimation;
204
60
  private _stopAllPromptAnimations;
61
+ /**
62
+ * Walk the raw config and ensure every control has a unique string `id`.
63
+ * Authors may omit `id`; this fills it in from `label` (slugified) with a
64
+ * collision suffix, or `ctrl_<index>` if `label` is also missing. Mutates
65
+ * the raw control objects in place — consistent with existing behavior
66
+ * (e.g. `aq.autocomplete` is fanned out onto controls below).
67
+ */
68
+ private _normalizeIds;
205
69
  private _flatControls;
206
70
  private _initValues;
207
- private _set;
208
71
  private _emitChange;
209
- private _renderBadge;
210
- private _renderDropdown;
211
- private _renderSegmented;
212
- private _renderRadio;
213
- private _renderToggle;
214
- private _renderSearch;
215
- private _renderComparison;
216
- private _renderThreshold;
217
- private _renderPreset;
218
- private static readonly _builtInFiltrexFns;
219
- private static _filtrexLoading;
220
- private static _getCompileExpression;
221
- private static _jsepLoading;
222
- private static _getJsep;
223
- private _handleSubmit;
224
- private _renderPrompt;
225
72
  private _renderControl;
73
+ /**
74
+ * If any prompt control in `controls` has its toggle enabled and is currently
75
+ * in NQL mode, collapse the visible set down to just that prompt — Basic mode
76
+ * shows everything, JQL mode shows only the expression input.
77
+ */
78
+ private _filterByPromptMode;
226
79
  private _renderGroup;
227
80
  render(): TemplateResult;
228
81
  }