@aquera/nile-visualization 2.9.2 → 2.9.4
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/dist/src/nile-chart/nile-chart.css.js +6 -0
- package/dist/src/nile-filter-chart/nile-filter-chart.css.js +274 -4
- package/dist/src/nile-filter-chart/nile-filter-chart.d.ts +59 -206
- package/dist/src/nile-filter-chart/nile-filter-chart.js +330 -436
- package/dist/src/nile-filter-chart/utils/badge.d.ts +3 -0
- package/dist/src/nile-filter-chart/utils/badge.js +33 -0
- package/dist/src/nile-filter-chart/utils/comparison.d.ts +3 -0
- package/dist/src/nile-filter-chart/utils/comparison.js +24 -0
- package/dist/src/nile-filter-chart/utils/dropdown.d.ts +3 -0
- package/dist/src/nile-filter-chart/utils/dropdown.js +24 -0
- package/dist/src/nile-filter-chart/utils/preset.d.ts +3 -0
- package/dist/src/nile-filter-chart/utils/preset.js +16 -0
- package/dist/src/nile-filter-chart/utils/prompt.d.ts +12 -0
- package/dist/src/nile-filter-chart/utils/prompt.js +676 -0
- package/dist/src/nile-filter-chart/utils/radio.d.ts +3 -0
- package/dist/src/nile-filter-chart/utils/radio.js +13 -0
- package/dist/src/nile-filter-chart/utils/search.d.ts +3 -0
- package/dist/src/nile-filter-chart/utils/search.js +12 -0
- package/dist/src/nile-filter-chart/utils/segmented.d.ts +3 -0
- package/dist/src/nile-filter-chart/utils/segmented.js +15 -0
- package/dist/src/nile-filter-chart/utils/threshold.d.ts +3 -0
- package/dist/src/nile-filter-chart/utils/threshold.js +58 -0
- package/dist/src/nile-filter-chart/utils/toggle.d.ts +3 -0
- package/dist/src/nile-filter-chart/utils/toggle.js +19 -0
- package/dist/src/nile-filter-chart/utils/types.d.ts +334 -0
- package/dist/src/nile-filter-chart/utils/types.js +2 -0
- package/dist/src/nile-kpi-chart/nile-kpi-chart.css.js +7 -4
- 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:
|
|
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
|
-
|
|
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-
|
|
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
|
-
|
|
4
|
-
export
|
|
5
|
-
|
|
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
|
-
|
|
8
|
+
selectedValues: Map<string, unknown>;
|
|
193
9
|
private collapsedGroups;
|
|
194
10
|
/** Currently displayed (animated) placeholder text per prompt-variant control id. */
|
|
195
|
-
|
|
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
|
}
|