@aquera/nile-visualization 2.9.8 → 2.9.10

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.
@@ -172,6 +172,15 @@ export const styles = css `
172
172
  contain: layout style;
173
173
  }
174
174
 
175
+ :host([no-header]) .nile-chart-inner {
176
+ border-radius: var(--nile-radius-radius-3xl, var(--ng-radius-xl));
177
+ padding-top: var(--nile-spacing-2xl, var(--ng-spacing-2xl));
178
+ }
179
+
180
+ :host([no-header][appearance="minimal"]) .nile-chart-inner {
181
+ padding-top: 0;
182
+ }
183
+
175
184
  /* Grid layout:
176
185
  - card uses clip-path (not overflow:hidden) so position:sticky on the header is not broken
177
186
  - height goes on nile-data-grid itself so .scroll-container inside shadow DOM scrolls,
@@ -459,21 +468,41 @@ export const styles = css `
459
468
  pointer-events: none;
460
469
  }
461
470
 
471
+ /* When loading, the card becomes a flex column that fills the host so the
472
+ skeleton can shrink with the container instead of forcing a fixed size. */
473
+ .nile-chart-card--loading {
474
+ display: flex;
475
+ flex-direction: column;
476
+ height: 100%;
477
+ }
478
+ .nile-chart-card--loading .nile-chart-wrapper {
479
+ flex: 1 1 auto;
480
+ min-height: 0;
481
+ }
482
+ .nile-chart-card--loading .nile-chart-inner {
483
+ height: 100%;
484
+ box-sizing: border-box;
485
+ }
486
+
462
487
  .nile-chart-skeleton {
463
488
  display: flex;
464
489
  flex-direction: column;
465
490
  gap: 0;
466
491
  padding: var(--nile-spacing-3xl, var(--ng-spacing-3xl)) var(--nile-spacing-3xl, var(--ng-spacing-3xl)) var(--nile-spacing-xl, var(--ng-spacing-xl));
467
- min-height: var(--nile-chart-skeleton-height, 300px);
492
+ height: 100%;
493
+ box-sizing: border-box;
494
+ overflow: hidden;
495
+ min-width: 0;
468
496
  }
469
497
 
470
498
  .nile-chart-skeleton-body {
471
499
  display: flex;
472
500
  flex-direction: column;
473
501
  justify-content: space-around;
474
- flex: 1;
502
+ flex: 1 1 auto;
503
+ min-height: 0;
475
504
  gap: var(--nile-spacing-14px, var(--ng-spacing-lg));
476
- padding-left: 44px;
505
+ padding-left: calc(var(--nile-spacing-5xl, var(--ng-spacing-5xl)) + var(--nile-spacing-xs, var(--ng-spacing-xs)));
477
506
  position: relative;
478
507
  }
479
508
 
@@ -484,8 +513,8 @@ export const styles = css `
484
513
  left: 34px;
485
514
  top: var(--nile-spacing-xs, var(--ng-spacing-xs));
486
515
  bottom: var(--nile-spacing-xs, var(--ng-spacing-xs));
487
- width: var(--nile-border-width-2, var(--ng-stroke-width-2));
488
- border-radius: var(--nile-border-width-1, var(--ng-stroke-width-1));
516
+ width: 4px;
517
+ border-radius: 2px;
489
518
  background: var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));
490
519
  }
491
520
 
@@ -493,59 +522,415 @@ export const styles = css `
493
522
  display: flex;
494
523
  align-items: center;
495
524
  gap: var(--nile-spacing-md, var(--ng-spacing-md));
496
- height: var(--nile-spacing-3xl, var(--ng-spacing-3xl));
525
+ flex: 1 1 0;
526
+ min-height: 0;
527
+ max-height: var(--nile-spacing-3xl, var(--ng-spacing-3xl));
528
+ }
529
+
530
+ .nile-chart-skeleton-row .nile-chart-skeleton-ylabel-sk { flex-shrink: 0; }
531
+ /* Horizontal bar — uses <nile-skeleton-loader>. The host takes flex-basis
532
+ w% (inline style); ::part(base) forces the inner wrapper to fill the
533
+ host so the shimmer rectangle spans the full w% of the row. */
534
+ .nile-chart-skeleton-bar-sk::part(base) {
535
+ width: 100%;
536
+ height: 100%;
497
537
  }
538
+ .nile-chart-skeleton-row:nth-child(1) .nile-chart-skeleton-bar-rect { animation-delay: 0ms; }
539
+ .nile-chart-skeleton-row:nth-child(2) .nile-chart-skeleton-bar-rect { animation-delay: 100ms; }
540
+ .nile-chart-skeleton-row:nth-child(3) .nile-chart-skeleton-bar-rect { animation-delay: 200ms; }
541
+ .nile-chart-skeleton-row:nth-child(4) .nile-chart-skeleton-bar-rect { animation-delay: 300ms; }
542
+ .nile-chart-skeleton-row:nth-child(5) .nile-chart-skeleton-bar-rect { animation-delay: 400ms; }
498
543
 
499
- .nile-chart-skeleton-ylabel {
500
- width: var(--nile-height-26px, 26px);
501
- height: var(--nile-spacing-10px, var(--ng-spacing-md-alt));
502
- border-radius: var(--nile-radius-radius-sm, var(--ng-radius-xs));
544
+ /* Horizontal x-axis labels row */
545
+ .nile-chart-skeleton-xaxis-row {
546
+ display: flex;
547
+ justify-content: space-around;
548
+ padding-left: calc(var(--nile-spacing-5xl, var(--ng-spacing-5xl)) + var(--nile-spacing-xs, var(--ng-spacing-xs)));
549
+ margin-top: var(--nile-spacing-14px, var(--ng-spacing-lg));
503
550
  flex-shrink: 0;
551
+ min-width: 0;
552
+ gap: var(--nile-spacing-sm, var(--ng-spacing-sm));
553
+ overflow: hidden;
554
+ }
555
+ .nile-chart-skeleton-xaxis-chip {
556
+ flex: 0 1 auto;
557
+ min-width: 0;
558
+ width: 30px;
559
+ max-width: 100%;
560
+ height: 10px;
504
561
  background: var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));
562
+ border-radius: var(--nile-radius-radius-md, var(--ng-radius-md));
505
563
  animation: nile-skeleton-blink 1.2s ease-in-out infinite;
506
564
  }
565
+ .nile-chart-skeleton-xaxis-row--columns .nile-chart-skeleton-xaxis-chip {
566
+ width: 24px;
567
+ }
568
+
569
+ /* Compact paddings + y-axis offset for narrow widths so the skeleton
570
+ doesn't overflow when the chart is shrunk. */
571
+ @container (max-width: 400px) {
572
+ .nile-chart-skeleton {
573
+ padding: var(--nile-spacing-xl, var(--ng-spacing-xl)) var(--nile-spacing-2xl, var(--ng-spacing-2xl)) var(--nile-spacing-lg, var(--ng-spacing-lg));
574
+ }
575
+ .nile-chart-skeleton-body { padding-left: var(--nile-spacing-4xl, var(--ng-spacing-4xl)); }
576
+ .nile-chart-skeleton-body::before { left: var(--nile-spacing-3xl, var(--ng-spacing-3xl)); }
577
+ .nile-chart-skeleton-xaxis-row { padding-left: var(--nile-spacing-4xl, var(--ng-spacing-4xl)); }
578
+ }
579
+
580
+ @container (max-width: 280px) {
581
+ .nile-chart-skeleton {
582
+ padding: var(--nile-spacing-lg, var(--ng-spacing-lg)) var(--nile-spacing-xl, var(--ng-spacing-xl));
583
+ }
584
+ .nile-chart-skeleton-body { padding-left: var(--nile-spacing-2xl, var(--ng-spacing-2xl)); }
585
+ .nile-chart-skeleton-body::before { left: var(--nile-spacing-14px, var(--ng-spacing-lg-alt)); }
586
+ .nile-chart-skeleton-xaxis-row {
587
+ padding-left: var(--nile-spacing-2xl, var(--ng-spacing-2xl));
588
+ gap: var(--nile-spacing-xs, var(--ng-spacing-xs));
589
+ }
590
+ .nile-chart-skeleton-ylabel { display: none; }
591
+ }
592
+
593
+ @container (max-width: 220px) {
594
+ .nile-chart-skeleton-xaxis-row { display: none; }
595
+ }
507
596
 
508
- .nile-chart-skeleton-bar {
509
- height: var(--nile-spacing-2xl, var(--ng-spacing-2xl));
510
- width: var(--w, 60%);
511
- border-radius: 0 var(--nile-radius-radius-sm, var(--ng-radius-xs)) var(--nile-radius-radius-sm, var(--ng-radius-xs)) 0;
597
+ @keyframes nile-skeleton-blink {
598
+ 0%, 100% { opacity: 0.5; }
599
+ 50% { opacity: 1; }
600
+ }
601
+
602
+ /* ── Variant: columns (vertical bars) — wraps nile-skeleton-loader ── */
603
+ .nile-chart-skeleton-columns {
604
+ display: flex;
605
+ align-items: flex-end;
606
+ justify-content: space-between;
607
+ gap: var(--nile-spacing-md, var(--ng-spacing-md));
608
+ flex: 1 1 auto;
609
+ min-height: 0;
610
+ padding-left: 28px;
611
+ position: relative;
612
+ }
613
+ .nile-chart-skeleton-columns::before,
614
+ .nile-chart-skeleton-columns::after {
615
+ content: '';
616
+ position: absolute;
617
+ background: var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));
618
+ border-radius: 1px;
619
+ }
620
+ .nile-chart-skeleton-columns::before { left: 18px; top: 0; bottom: 0; width: 2px; }
621
+ .nile-chart-skeleton-columns::after { left: 18px; right: 0; bottom: 0; height: 2px; }
622
+ .nile-chart-skeleton-col-cell {
623
+ flex: 1 1 0;
624
+ min-width: 0;
625
+ height: 60%;
626
+ display: flex;
627
+ align-items: stretch;
628
+ border-radius: var(--nile-radius-radius-sm, var(--ng-radius-xs)) var(--nile-radius-radius-sm, var(--ng-radius-xs)) 0 0;
629
+ overflow: hidden;
630
+ }
631
+ .nile-chart-skeleton-xaxis-row--columns { padding-left: 28px; }
632
+
633
+ .nile-chart-skeleton-fill {
634
+ width: 100%;
635
+ height: 100%;
636
+ background: var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));
637
+ border-radius: inherit;
638
+ animation: nile-skeleton-blink 1.2s ease-in-out infinite;
639
+ }
640
+
641
+ /* ── Variant: line ── */
642
+ .nile-chart-skeleton-line {
643
+ flex: 1 1 auto;
644
+ min-height: 0;
645
+ padding-left: 28px;
646
+ position: relative;
647
+ }
648
+ .nile-chart-skeleton-line::before {
649
+ content: '';
650
+ position: absolute;
651
+ left: 18px; top: 0; bottom: 0;
652
+ width: 2px;
653
+ border-radius: 1px;
512
654
  background: var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));
655
+ }
656
+ .nile-chart-skeleton-line svg { width: 100%; height: 100%; display: block; }
657
+ .nile-chart-skeleton-line-area {
658
+ fill: var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));
659
+ opacity: 0.35;
660
+ animation: nile-skeleton-blink 1.6s ease-in-out infinite;
661
+ }
662
+ .nile-chart-skeleton-line-stroke {
663
+ fill: none;
664
+ stroke: var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));
665
+ stroke-width: 1.6;
666
+ stroke-linecap: round;
667
+ stroke-linejoin: round;
668
+ animation: nile-skeleton-blink 1.2s ease-in-out infinite;
669
+ }
670
+
671
+ /* Trendline: faint guide line + actuals stroke + dashed forecast + split rule */
672
+ .nile-chart-skeleton-trend-line {
673
+ stroke: var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));
674
+ stroke-width: 0.8;
675
+ opacity: 0.45;
676
+ }
677
+ .nile-chart-skeleton-trend-forecast {
678
+ fill: none;
679
+ stroke: var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));
680
+ stroke-width: 1.6;
681
+ stroke-linecap: round;
682
+ stroke-dasharray: 3 3;
513
683
  animation: nile-skeleton-blink 1.2s ease-in-out infinite;
684
+ animation-delay: 200ms;
685
+ }
686
+ .nile-chart-skeleton-trend-divider {
687
+ stroke: var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));
688
+ stroke-width: 0.5;
689
+ stroke-dasharray: 1 2;
690
+ opacity: 0.5;
514
691
  }
515
692
 
516
- /* Staggered wave across the bars */
517
- .nile-chart-skeleton-row:nth-child(1) .nile-chart-skeleton-bar { animation-delay: 0ms; }
518
- .nile-chart-skeleton-row:nth-child(2) .nile-chart-skeleton-bar { animation-delay: 100ms; }
519
- .nile-chart-skeleton-row:nth-child(3) .nile-chart-skeleton-bar { animation-delay: 200ms; }
520
- .nile-chart-skeleton-row:nth-child(4) .nile-chart-skeleton-bar { animation-delay: 300ms; }
521
- .nile-chart-skeleton-row:nth-child(5) .nile-chart-skeleton-bar { animation-delay: 400ms; }
693
+ /* Anomaly: halo pulses around outlier dots, dot itself blinks */
694
+ .nile-chart-skeleton-anomaly-dot {
695
+ fill: var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));
696
+ animation: nile-skeleton-blink 1.1s ease-in-out infinite;
697
+ }
698
+ .nile-chart-skeleton-anomaly-halo {
699
+ fill: var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));
700
+ opacity: 0.25;
701
+ transform-origin: center;
702
+ transform-box: fill-box;
703
+ animation: nile-skeleton-anomaly-pulse 1.8s ease-in-out infinite;
704
+ }
705
+ .nile-chart-skeleton-anomaly-halo:nth-of-type(1) { animation-delay: 0ms; }
706
+ .nile-chart-skeleton-anomaly-halo:nth-of-type(2) { animation-delay: 300ms; }
707
+ .nile-chart-skeleton-anomaly-halo:nth-of-type(3) { animation-delay: 600ms; }
708
+ @keyframes nile-skeleton-anomaly-pulse {
709
+ 0%, 100% { opacity: 0.15; transform: scale(0.7); }
710
+ 50% { opacity: 0.35; transform: scale(1.2); }
711
+ }
522
712
 
523
- /* Horizontal x-axis labels row */
524
- .nile-chart-skeleton-xaxis-row {
713
+ /* ── Variant: pie / donut ── */
714
+ .nile-chart-skeleton-pie-wrap {
525
715
  display: flex;
526
- justify-content: space-around;
527
- padding-left: 44px;
528
- margin-top: var(--nile-spacing-14px, var(--ng-spacing-lg));
716
+ align-items: center;
717
+ justify-content: center;
718
+ gap: var(--nile-spacing-3xl, var(--ng-spacing-3xl));
719
+ flex: 1 1 auto;
720
+ min-height: 0;
721
+ container-type: size;
722
+ }
723
+ .nile-chart-skeleton-pie {
724
+ width: min(60cqmin, var(--nile-width-208px, 208px));
725
+ aspect-ratio: 1;
726
+ border-radius: 50%;
727
+ background: conic-gradient(
728
+ var(--nile-colors-neutral-400, var(--ng-colors-border-secondary)) 0 25%,
729
+ var(--nile-colors-neutral-300, #e5e7eb) 25% 55%,
730
+ var(--nile-colors-neutral-400, var(--ng-colors-border-secondary)) 55% 80%,
731
+ var(--nile-colors-neutral-300, #e5e7eb) 80% 100%
732
+ );
733
+ mask: radial-gradient(circle, transparent 28%, black 30%);
734
+ -webkit-mask: radial-gradient(circle, transparent 28%, black 30%);
735
+ animation: nile-skeleton-spin 6s linear infinite, nile-skeleton-blink 1.6s ease-in-out infinite;
736
+ }
737
+ .nile-chart-skeleton-legend {
738
+ display: flex;
739
+ flex-direction: column;
740
+ gap: var(--nile-spacing-md, var(--ng-spacing-md));
741
+ flex-shrink: 0;
529
742
  }
743
+ .nile-chart-skeleton-legend-row {
744
+ display: flex;
745
+ align-items: center;
746
+ gap: var(--nile-spacing-sm, var(--ng-spacing-sm));
747
+ }
748
+ @container (max-width: 320px) {
749
+ .nile-chart-skeleton-legend { display: none; }
750
+ }
751
+ @keyframes nile-skeleton-spin { to { transform: rotate(360deg); } }
530
752
 
531
- .nile-chart-skeleton-xlabel {
532
- height: var(--nile-spacing-10px, var(--ng-spacing-md-alt));
533
- width: var(--nile-height-30px, 30px);
534
- border-radius: var(--nile-radius-radius-sm, var(--ng-radius-xs));
753
+ /* ── Variant: scatter ── */
754
+ .nile-chart-skeleton-scatter {
755
+ flex: 1 1 auto;
756
+ min-height: 0;
757
+ position: relative;
758
+ padding-left: 28px;
759
+ }
760
+ .nile-chart-skeleton-scatter::before,
761
+ .nile-chart-skeleton-scatter::after {
762
+ content: '';
763
+ position: absolute;
535
764
  background: var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));
765
+ border-radius: 1px;
766
+ }
767
+ .nile-chart-skeleton-scatter::before { left: 18px; top: 0; bottom: 0; width: 2px; }
768
+ .nile-chart-skeleton-scatter::after { left: 18px; right: 0; bottom: 0; height: 2px; }
769
+ .nile-chart-skeleton-dot-pos {
770
+ position: absolute;
771
+ transform: translate(-50%, -50%);
772
+ display: inline-flex;
773
+ }
774
+
775
+ /* ── Variant: heatmap ── */
776
+ .nile-chart-skeleton-heatmap {
777
+ display: flex;
778
+ flex-direction: column;
779
+ gap: var(--nile-spacing-sm, var(--ng-spacing-sm));
780
+ flex: 1 1 auto;
781
+ min-height: 0;
782
+ }
783
+ .nile-chart-skeleton-heatmap-row {
784
+ display: flex;
785
+ gap: var(--nile-spacing-sm, var(--ng-spacing-sm));
786
+ flex: 1 1 0;
787
+ min-height: 0;
788
+ }
789
+ .nile-chart-skeleton-heatmap-cell {
790
+ flex: 1 1 0;
791
+ min-width: 0;
792
+ display: flex;
793
+ border-radius: var(--nile-radius-radius-md, var(--ng-radius-md));
794
+ overflow: hidden;
795
+ }
796
+
797
+ /* ── Variant: radar ── */
798
+ .nile-chart-skeleton-radar-wrap {
799
+ display: flex;
800
+ align-items: center;
801
+ justify-content: center;
802
+ flex: 1 1 auto;
803
+ min-height: 0;
804
+ min-width: 0;
805
+ container-type: size;
806
+ overflow: hidden;
807
+ }
808
+ .nile-chart-skeleton-radar-svg {
809
+ width: min(78cqmin, var(--nile-width-240px, 240px));
810
+ height: min(78cqmin, var(--nile-width-240px, 240px));
811
+ display: block;
812
+ }
813
+ .nile-chart-skeleton-radar-grid {
814
+ fill: none;
815
+ stroke: var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));
816
+ stroke-width: 0.8;
817
+ stroke-linejoin: round;
818
+ opacity: 0.7;
819
+ }
820
+ .nile-chart-skeleton-radar-spoke {
821
+ stroke: var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));
822
+ stroke-width: 0.6;
823
+ opacity: 0.5;
824
+ }
825
+ .nile-chart-skeleton-radar-data {
826
+ fill: var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));
827
+ stroke: var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));
828
+ stroke-width: 1.2;
829
+ stroke-linejoin: round;
830
+ opacity: 0.45;
831
+ animation: nile-skeleton-blink 1.4s ease-in-out infinite;
832
+ transform-origin: 50px 50px;
833
+ transform-box: fill-box;
834
+ }
835
+ .nile-chart-skeleton-radar-dot {
836
+ fill: var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));
536
837
  animation: nile-skeleton-blink 1.2s ease-in-out infinite;
537
- animation-delay: var(--d, 0ms);
538
838
  }
839
+ .nile-chart-skeleton-radar-dot:nth-child(5) { animation-delay: 0ms; }
840
+ .nile-chart-skeleton-radar-dot:nth-child(6) { animation-delay: 120ms; }
841
+ .nile-chart-skeleton-radar-dot:nth-child(7) { animation-delay: 240ms; }
842
+ .nile-chart-skeleton-radar-dot:nth-child(8) { animation-delay: 360ms; }
843
+ .nile-chart-skeleton-radar-dot:nth-child(9) { animation-delay: 480ms; }
539
844
 
540
- @keyframes nile-skeleton-blink {
541
- 0%, 100% { opacity: 0.5; }
542
- 50% { opacity: 1; }
845
+ /* ── Variant: timeline ── */
846
+ .nile-chart-skeleton-timeline {
847
+ display: flex;
848
+ flex-direction: column;
849
+ gap: var(--nile-spacing-sm, var(--ng-spacing-sm));
850
+ flex: 1 1 auto;
851
+ min-height: 0;
852
+ justify-content: space-around;
853
+ overflow: hidden;
854
+ }
855
+ .nile-chart-skeleton-tl-row {
856
+ position: relative;
857
+ flex: 1 1 0;
858
+ min-height: 0;
859
+ max-height: var(--nile-height-12px, var(--ng-height-12px));
860
+ }
861
+ .nile-chart-skeleton-tl-bar-pos {
862
+ position: absolute;
863
+ top: 0; bottom: 0;
864
+ display: inline-flex;
865
+ border-radius: var(--nile-radius-radius-lg, var(--ng-radius-sm));
866
+ }
867
+
868
+ /* ── Variant: kpi ── */
869
+ .nile-chart-skeleton-kpi {
870
+ display: flex;
871
+ flex-direction: column;
872
+ gap: var(--nile-spacing-md, var(--ng-spacing-md));
873
+ flex: 1 1 auto;
874
+ min-height: 0;
875
+ justify-content: center;
876
+ }
877
+ .nile-chart-skeleton-kpi-spark {
878
+ width: 100%;
879
+ height: 40px;
880
+ margin-top: var(--nile-spacing-sm, var(--ng-spacing-sm));
881
+ }
882
+ .nile-chart-skeleton-kpi-spark path {
883
+ fill: none;
884
+ stroke: var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));
885
+ stroke-width: 1.6;
886
+ stroke-linecap: round;
887
+ stroke-linejoin: round;
888
+ animation: nile-skeleton-blink 1.2s ease-in-out infinite;
889
+ }
890
+
891
+ /* ── Variant: grid (table) ── */
892
+ .nile-chart-skeleton-grid {
893
+ display: flex;
894
+ flex-direction: column;
895
+ gap: var(--nile-spacing-sm, var(--ng-spacing-sm));
896
+ flex: 1 1 auto;
897
+ min-height: 0;
898
+ }
899
+ .nile-chart-skeleton-grid-head,
900
+ .nile-chart-skeleton-grid-row {
901
+ display: flex;
902
+ gap: var(--nile-spacing-md, var(--ng-spacing-md));
903
+ align-items: center;
904
+ flex: 1 1 0;
905
+ min-height: 0;
906
+ max-height: 28px;
907
+ }
908
+ .nile-chart-skeleton-grid-head {
909
+ border-bottom: 1px solid var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));
910
+ padding-bottom: var(--nile-spacing-sm, var(--ng-spacing-sm));
911
+ }
912
+ .nile-chart-skeleton-grid-head nile-skeleton-loader,
913
+ .nile-chart-skeleton-grid-row nile-skeleton-loader {
914
+ flex: 1 1 0;
915
+ min-width: 0;
916
+ }
917
+
918
+ /* ── Variant: filter ── */
919
+ .nile-chart-skeleton-filter {
920
+ display: flex;
921
+ flex-direction: column;
922
+ flex: 1 1 auto;
923
+ min-height: 0;
924
+ justify-content: center;
543
925
  }
544
926
 
545
927
  @media (prefers-reduced-motion: reduce) {
546
- .nile-chart-skeleton-bar,
547
- .nile-chart-skeleton-ylabel,
548
- .nile-chart-skeleton-xlabel {
928
+ .nile-chart-skeleton-line-area,
929
+ .nile-chart-skeleton-line-stroke,
930
+ .nile-chart-skeleton-pie,
931
+ .nile-chart-skeleton-radar-data,
932
+ .nile-chart-skeleton-radar-dot,
933
+ .nile-chart-skeleton-kpi-spark path {
549
934
  animation: none;
550
935
  opacity: 0.7;
551
936
  }
@@ -66,6 +66,8 @@ export declare class NileChart extends NileElement {
66
66
  * ```
67
67
  */
68
68
  loading: boolean;
69
+ noHeader: boolean;
70
+ appearance: string | null;
69
71
  /**
70
72
  * When set, fills `chart.type` if the config omits it (same values as `chart.type`, e.g. `stacked`, `pie`).
71
73
  * Usage: `<nile-chart chart-type="pie" />` plus `config.chart` with series data only.
@@ -73,6 +75,7 @@ export declare class NileChart extends NileElement {
73
75
  chartTypeAttr: string;
74
76
  /** Summary/insight text — shown as the AI panel's opening message when the chat is opened. */
75
77
  summary: string;
78
+ aiBorder: boolean;
76
79
  /**
77
80
  * Controls which items appear in the actions menu. All items are opt-in —
78
81
  * only items explicitly set to `true` are shown. Merged with (and takes
@@ -4,6 +4,7 @@ import { html, nothing } from 'lit';
4
4
  import NileElement from '../internal/nile-element.js';
5
5
  import { styles, tooltipCss } from './nile-chart.css.js';
6
6
  import { nileChartConfig } from './nile-chart-config-builder.js';
7
+ import { renderChartSkeleton } from './nile-chart-skeleton.js';
7
8
  import { convertConfig } from '../internal/chart-adapters.js';
8
9
  import { deepMerge } from '../internal/utils.js';
9
10
  import { initNileChartExporting, getHighcharts } from '../internal/highcharts-provider.js';
@@ -135,6 +136,8 @@ let NileChart = class NileChart extends NileElement {
135
136
  * ```
136
137
  */
137
138
  this.loading = false;
139
+ this.noHeader = false;
140
+ this.appearance = null;
138
141
  /**
139
142
  * When set, fills `chart.type` if the config omits it (same values as `chart.type`, e.g. `stacked`, `pie`).
140
143
  * Usage: `<nile-chart chart-type="pie" />` plus `config.chart` with series data only.
@@ -142,6 +145,7 @@ let NileChart = class NileChart extends NileElement {
142
145
  this.chartTypeAttr = '';
143
146
  /** Summary/insight text — shown as the AI panel's opening message when the chat is opened. */
144
147
  this.summary = '';
148
+ this.aiBorder = false;
145
149
  /**
146
150
  * Controls which items appear in the actions menu. All items are opt-in —
147
151
  * only items explicitly set to `true` are shown. Merged with (and takes
@@ -248,6 +252,14 @@ let NileChart = class NileChart extends NileElement {
248
252
  this.resolvedConfig = this.resolveConfig(this.config);
249
253
  this.activeType = this.resolvedConfig.type;
250
254
  this.activeConfig = this.resolvedConfig;
255
+ const resolved = this.resolvedConfig;
256
+ // appearance="minimal" on filter charts implies a header-less compact layout.
257
+ const minimalFilter = resolved.type === 'filter' && resolved.appearance === 'minimal';
258
+ const cfgNoHeader = resolved.noHeader === true || minimalFilter;
259
+ if (cfgNoHeader && !this.noHeader)
260
+ this.noHeader = true;
261
+ if (resolved.appearance && this.appearance !== resolved.appearance)
262
+ this.appearance = resolved.appearance;
251
263
  }
252
264
  }
253
265
  toggleMenu(e) {
@@ -360,6 +372,12 @@ let NileChart = class NileChart extends NileElement {
360
372
  return false;
361
373
  }
362
374
  shouldShowHeader() {
375
+ if (this.noHeader)
376
+ return false;
377
+ if (this.resolvedConfig?.noHeader === true)
378
+ return false;
379
+ if (this.activeConfig?.noHeader === true)
380
+ return false;
363
381
  const hasTitles = !!(this.headerTitle || this.headerSubtitle);
364
382
  const menuEnabled = this.resolvedConfig?.menu?.enabled === true || this.menu?.enabled === true;
365
383
  const hasBuiltinActions = this.aiEnabled || (this.resolvedConfig?.switchableTypes?.length ?? 0) > 0 || menuEnabled;
@@ -1697,8 +1715,11 @@ let NileChart = class NileChart extends NileElement {
1697
1715
  }
1698
1716
  case 'filter': {
1699
1717
  const promote = this.isPromotableFilter;
1718
+ const filterConfig = this.aiBorder
1719
+ ? { ...config, controls: config.controls.map(c => ({ ...c, aiBorder: c.aiBorder ?? true })) }
1720
+ : config;
1700
1721
  return html `<nile-filter-chart
1701
- .config=${{ chart: config }}
1722
+ .config=${{ chart: filterConfig }}
1702
1723
  ?hide-control-headers=${promote}
1703
1724
  @nile-change="${(e) => this.emit('nile-change', e.detail)}"
1704
1725
  ></nile-filter-chart>`;
@@ -1710,27 +1731,13 @@ let NileChart = class NileChart extends NileElement {
1710
1731
  }
1711
1732
  }
1712
1733
  renderSkeleton() {
1713
- return html `
1714
- <div class="nile-chart-skeleton" aria-busy="true" aria-label="Loading chart">
1715
- <div class="nile-chart-skeleton-body">
1716
- ${[78, 55, 91, 42, 68].map(w => html `
1717
- <div class="nile-chart-skeleton-row">
1718
- <div class="nile-chart-skeleton-ylabel"></div>
1719
- <div class="nile-chart-skeleton-bar" style="--w: ${w}%"></div>
1720
- </div>
1721
- `)}
1722
- </div>
1723
- <div class="nile-chart-skeleton-xaxis-row">
1724
- ${[0, 1, 2, 3, 4].map(i => html `<div class="nile-chart-skeleton-xlabel" style="--d: ${i * 80}ms"></div>`)}
1725
- </div>
1726
- </div>
1727
- `;
1734
+ return renderChartSkeleton(this.activeConfig?.type);
1728
1735
  }
1729
1736
  render() {
1730
1737
  const isLoading = this.loading || (this.activeConfig?.loading ?? false);
1731
1738
  const isGrid = this.activeConfig?.type === 'grid';
1732
1739
  return html `
1733
- <div class="nile-chart-card ${isGrid ? 'nile-chart-card--grid' : ''}" part="chart-card">
1740
+ <div class="nile-chart-card ${isGrid ? 'nile-chart-card--grid' : ''} ${isLoading ? 'nile-chart-card--loading' : ''}" part="chart-card">
1734
1741
  ${this.renderHeader()}
1735
1742
  <div class="nile-chart-wrapper">
1736
1743
  <div class="nile-chart-inner ${this.activeConfig?.type === 'kpi' ? 'nile-chart-inner--kpi' : ''} ${this.activeConfig?.type === 'filter' ? 'nile-chart-inner--filter' : ''}" part="chart-inner">
@@ -1755,12 +1762,21 @@ __decorate([
1755
1762
  __decorate([
1756
1763
  property({ type: Boolean, reflect: true })
1757
1764
  ], NileChart.prototype, "loading", void 0);
1765
+ __decorate([
1766
+ property({ type: Boolean, reflect: true, attribute: 'no-header' })
1767
+ ], NileChart.prototype, "noHeader", void 0);
1768
+ __decorate([
1769
+ property({ type: String, reflect: true })
1770
+ ], NileChart.prototype, "appearance", void 0);
1758
1771
  __decorate([
1759
1772
  property({ type: String, attribute: 'chart-type' })
1760
1773
  ], NileChart.prototype, "chartTypeAttr", void 0);
1761
1774
  __decorate([
1762
1775
  property({ type: String })
1763
1776
  ], NileChart.prototype, "summary", void 0);
1777
+ __decorate([
1778
+ property({ type: Boolean, reflect: true, attribute: 'ai-border' })
1779
+ ], NileChart.prototype, "aiBorder", void 0);
1764
1780
  __decorate([
1765
1781
  property({ type: Object })
1766
1782
  ], NileChart.prototype, "menu", void 0);