@aquera/nile-visualization 0.4.0 → 0.6.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.
Files changed (47) hide show
  1. package/dist/src/index.d.ts +8 -2
  2. package/dist/src/index.js +3 -0
  3. package/dist/src/internal/dashboard-adapters.d.ts +13 -0
  4. package/dist/src/internal/dashboard-adapters.js +123 -0
  5. package/dist/src/internal/highcharts-provider.js +27 -0
  6. package/dist/src/internal/types/chart-config.type.d.ts +2 -1
  7. package/dist/src/internal/types/chart-kpi-config.type.d.ts +5 -21
  8. package/dist/src/internal/types/chart-map-config.type.d.ts +29 -0
  9. package/dist/src/internal/types/chart-map-config.type.js +2 -0
  10. package/dist/src/internal/types/dashboard-config.type.d.ts +8 -0
  11. package/dist/src/internal/types/dashboard-config.type.js +2 -0
  12. package/dist/src/internal/types/index.d.ts +2 -1
  13. package/dist/src/internal/types/primitive-chart-config.type.d.ts +2 -1
  14. package/dist/src/internal/types/widget-config.type.d.ts +23 -0
  15. package/dist/src/internal/types/widget-config.type.js +2 -0
  16. package/dist/src/internal/types/widget-layout.type.d.ts +11 -0
  17. package/dist/src/internal/types/widget-layout.type.js +2 -0
  18. package/dist/src/nile-ai-panel/nile-ai-panel.css.js +8 -0
  19. package/dist/src/nile-ai-panel/nile-ai-panel.d.ts +2 -0
  20. package/dist/src/nile-ai-panel/nile-ai-panel.js +8 -0
  21. package/dist/src/nile-chart/index.d.ts +2 -2
  22. package/dist/src/nile-chart/nile-chart-config.d.ts +121 -29
  23. package/dist/src/nile-chart/nile-chart.css.js +32 -7
  24. package/dist/src/nile-chart/nile-chart.d.ts +23 -7
  25. package/dist/src/nile-chart/nile-chart.js +148 -49
  26. package/dist/src/nile-dashboard-viewer/index.d.ts +2 -0
  27. package/dist/src/nile-dashboard-viewer/index.js +2 -0
  28. package/dist/src/nile-dashboard-viewer/nile-dashboard-viewer.css.d.ts +1 -0
  29. package/dist/src/nile-dashboard-viewer/nile-dashboard-viewer.css.js +29 -0
  30. package/dist/src/nile-dashboard-viewer/nile-dashboard-viewer.d.ts +43 -0
  31. package/dist/src/nile-dashboard-viewer/nile-dashboard-viewer.js +84 -0
  32. package/dist/src/nile-kpi-chart/nile-kpi-chart.css.js +4 -4
  33. package/dist/src/nile-kpi-chart/nile-kpi-chart.d.ts +2 -0
  34. package/dist/src/nile-kpi-chart/nile-kpi-chart.js +6 -0
  35. package/dist/src/nile-map-chart/index.d.ts +2 -0
  36. package/dist/src/nile-map-chart/index.js +2 -0
  37. package/dist/src/nile-map-chart/nile-map-chart.css.d.ts +1 -0
  38. package/dist/src/nile-map-chart/nile-map-chart.css.js +28 -0
  39. package/dist/src/nile-map-chart/nile-map-chart.d.ts +74 -0
  40. package/dist/src/nile-map-chart/nile-map-chart.js +263 -0
  41. package/dist/src/nile-widget-viewer/index.d.ts +3 -0
  42. package/dist/src/nile-widget-viewer/index.js +2 -0
  43. package/dist/src/nile-widget-viewer/nile-widget-viewer.css.d.ts +1 -0
  44. package/dist/src/nile-widget-viewer/nile-widget-viewer.css.js +20 -0
  45. package/dist/src/nile-widget-viewer/nile-widget-viewer.d.ts +33 -0
  46. package/dist/src/nile-widget-viewer/nile-widget-viewer.js +50 -0
  47. package/package.json +4 -2
@@ -13,7 +13,7 @@ export const styles = css `
13
13
  /* ── Unified Card Container ── */
14
14
 
15
15
  .chart-card {
16
- background: var(--nile-colors-white-base, var(--ng-colors-bg-quaternary-alt));
16
+ background: var(--nile-colors-white-base, var(--ng-colors-bg-primary));
17
17
  border: var(--nile-border-width-1, var(--ng-stroke-width-1)) solid var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));
18
18
  border-radius: var(--nile-radius-radius-3xl, var(--ng-radius-xl));
19
19
  box-shadow: var(--nile-box-shadow-3, var(--ng-shadow-sm));
@@ -33,7 +33,7 @@ export const styles = css `
33
33
  position: relative;
34
34
  z-index: 10;
35
35
  padding: var(--nile-spacing-2xl, var(--ng-spacing-2xl)) var(--nile-spacing-3xl, var(--ng-spacing-3xl)) var(--nile-spacing-xl, var(--ng-spacing-xl));
36
- background: var(--nile-colors-white-base, var(--ng-colors-bg-primary));
36
+ background: transparent;
37
37
  border-bottom: var(--nile-border-width-1, var(--ng-stroke-width-1)) solid var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));
38
38
  border-radius: var(--nile-radius-radius-3xl, var(--ng-radius-xl)) var(--nile-radius-radius-3xl, var(--ng-radius-xl)) 0 0;
39
39
  }
@@ -82,10 +82,35 @@ export const styles = css `
82
82
  contain: layout style;
83
83
  }
84
84
 
85
- ::slotted(*) {
85
+ /* ── Default slot (custom chart body only — not named slots) ── */
86
+ slot:not([name])::slotted(*) {
87
+ display: block;
86
88
  width: 100%;
87
89
  }
88
90
 
91
+ /* ── header / header-actions slots (one row; built-in AI + switcher on the right) ── */
92
+ slot[name='header']::slotted(*) {
93
+ display: block;
94
+ width: 100%;
95
+ }
96
+
97
+ slot[name='header-actions']::slotted(*) {
98
+ display: inline-flex;
99
+ align-items: center;
100
+ gap: var(--nile-spacing-xs, var(--ng-spacing-xs));
101
+ }
102
+
103
+ /* ── footer slot ── */
104
+ slot[name='footer']::slotted(*) {
105
+ display: block;
106
+ margin: 0;
107
+ padding: var(--nile-spacing-xl, var(--ng-spacing-xl)) var(--nile-spacing-3xl, var(--ng-spacing-3xl));
108
+ border-top: var(--nile-border-width-1, var(--ng-stroke-width-1)) solid var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));
109
+ font-family: var(--nile-font-family-serif, var(--ng-font-family-body));
110
+ font-size: var(--nile-type-scale-2, var(--ng-font-size-text-xs));
111
+ color: var(--nile-colors-neutral-700, var(--ng-colors-text-secondary-700));
112
+ }
113
+
89
114
  nile-bar-chart,
90
115
  nile-pie-chart,
91
116
  nile-trendline-chart,
@@ -128,7 +153,7 @@ export const styles = css `
128
153
  }
129
154
 
130
155
  .chart-toggle:hover {
131
- background: var(--nile-colors-neutral-100, var(--ng-colors-bg-secondary));
156
+ background: var(--nile-colors-white-base, var(--ng-colors-bg-primary));
132
157
  box-shadow: var(--nile-box-shadow-3, var(--ng-shadow-sm));
133
158
  }
134
159
 
@@ -188,7 +213,7 @@ export const styles = css `
188
213
  }
189
214
 
190
215
  .chart-menu-trigger:hover {
191
- background: var(--nile-colors-neutral-100, var(--ng-colors-bg-secondary));
216
+ background: transparent;
192
217
  color: var(--nile-colors-dark-900, var(--ng-colors-text-primary-900));
193
218
  }
194
219
 
@@ -228,7 +253,7 @@ export const styles = css `
228
253
  }
229
254
 
230
255
  .chart-menu-item:hover {
231
- background: var(--nile-colors-neutral-100, var(--ng-colors-bg-secondary));
256
+ background: transparent;
232
257
  }
233
258
 
234
259
  .chart-menu-item.active {
@@ -259,7 +284,7 @@ export const styles = css `
259
284
  }
260
285
 
261
286
  .ai-trigger:hover {
262
- background: var(--nile-colors-neutral-100, var(--ng-colors-bg-secondary));
287
+ background: transparent;
263
288
  color: var(--nile-colors-primary-600, var(--ng-colors-fg-brand-primary-600));
264
289
  }
265
290
 
@@ -16,6 +16,7 @@ import '../nile-spline-chart/index.js';
16
16
  import '../nile-radar-chart/index.js';
17
17
  import '../nile-gauge-chart/index.js';
18
18
  import '../nile-waterfall-chart/index.js';
19
+ import '../nile-map-chart/index.js';
19
20
  import '../nile-cluster-chart/index.js';
20
21
  import '../nile-stacked-chart/index.js';
21
22
  import '../nile-histogram-chart/index.js';
@@ -46,6 +47,7 @@ import '../nile-euler-chart/index.js';
46
47
  import '../nile-polygon-chart/index.js';
47
48
  import '../nile-vector-chart/index.js';
48
49
  import '../nile-xrange-chart/index.js';
50
+ import '../nile-kpi-chart/index.js';
49
51
  import '../nile-ai-panel/index.js';
50
52
  export declare class NileChart extends NileElement {
51
53
  static styles: CSSResultGroup;
@@ -56,19 +58,27 @@ export declare class NileChart extends NileElement {
56
58
  * Usage: `<nile-chart chart-type="pie" />` plus `config.chart` with series data only.
57
59
  */
58
60
  chartTypeAttr: string;
59
- /** The summary/insight text displayed in the overlay (fallback when config is not set). */
61
+ /** Summary/insight text shown as the AI panel's opening message when the chat is opened. */
62
+ /**
63
+ * When set, fills `chart.type` if the config omits it (same values as `chart.type`, e.g. `stacked`, `pie`).
64
+ * Usage: `<nile-chart chart-type="pie" />` plus `config.chart` with series data only.
65
+ */
66
+ /** Summary/insight text — shown as the AI panel's opening message when the chat is opened. */
60
67
  summary: string;
61
- /** Label for the toggle button (fallback when config is not set). */
62
- toggleLabel: string;
63
- /** Whether the insight overlay is visible. */
64
- open: boolean;
65
68
  private activeType;
66
69
  private activeConfig;
67
70
  private menuOpen;
68
71
  private chatOpen;
72
+ /** True when elements are projected into the `header` slot (default title/subtitle hidden). */
73
+ private hasHeaderSlotContent;
74
+ /** True when elements are projected into `header-actions` (used to show the header row). */
75
+ private hasHeaderActionsSlot;
76
+ /** True when elements are projected into the `header` slot (default title/subtitle hidden). */
77
+ /** True when elements are projected into `header-actions` (used to show the header row). */
69
78
  private aiPanel;
70
79
  private get effectiveSummary();
71
- private get effectiveToggleLabel();
80
+ /** AI panel shows when ai.enabled is true OR when a summary is provided. */
81
+ /** AI panel shows when ai.enabled is true OR when a summary is provided. */
72
82
  private get aiEnabled();
73
83
  private handleOutsideClick;
74
84
  connectedCallback(): void;
@@ -78,7 +88,6 @@ export declare class NileChart extends NileElement {
78
88
  private resolveConfig;
79
89
  private resolvedConfig;
80
90
  protected updated(changedProperties: PropertyValues): void;
81
- private toggle;
82
91
  private toggleMenu;
83
92
  private toggleChat;
84
93
  /** Push an AI response into the chat panel. Call this from your AI handler. */
@@ -87,6 +96,13 @@ export declare class NileChart extends NileElement {
87
96
  private switchType;
88
97
  private get headerTitle();
89
98
  private get headerSubtitle();
99
+ private onHeaderSlotChange;
100
+ private onHeaderActionsSlotChange;
101
+ private syncHeaderSlots;
102
+ protected firstUpdated(changedProperties: PropertyValues): void;
103
+ /** Direct children with `slot=` — header row renders on first paint before slot assignment runs. */
104
+ private lightDomHasSlot;
105
+ private shouldShowHeader;
90
106
  private renderTypeSwitcher;
91
107
  private renderAiTrigger;
92
108
  private renderHeader;
@@ -19,6 +19,7 @@ import '../nile-spline-chart/index.js';
19
19
  import '../nile-radar-chart/index.js';
20
20
  import '../nile-gauge-chart/index.js';
21
21
  import '../nile-waterfall-chart/index.js';
22
+ import '../nile-map-chart/index.js';
22
23
  import '../nile-cluster-chart/index.js';
23
24
  import '../nile-stacked-chart/index.js';
24
25
  import '../nile-histogram-chart/index.js';
@@ -49,6 +50,7 @@ import '../nile-euler-chart/index.js';
49
50
  import '../nile-polygon-chart/index.js';
50
51
  import '../nile-vector-chart/index.js';
51
52
  import '../nile-xrange-chart/index.js';
53
+ import '../nile-kpi-chart/index.js';
52
54
  import '../nile-ai-panel/index.js';
53
55
  const CORE_CHART_LABELS = {
54
56
  bar: 'Bar',
@@ -65,6 +67,7 @@ const CORE_CHART_LABELS = {
65
67
  radar: 'Radar',
66
68
  gauge: 'Gauge',
67
69
  waterfall: 'Waterfall',
70
+ map: 'Map',
68
71
  stacked: 'Stacked column',
69
72
  cluster: 'Cluster',
70
73
  histogram: 'Histogram',
@@ -84,6 +87,7 @@ const CORE_CHART_LABELS = {
84
87
  xrange: 'X-range',
85
88
  lollipop: 'Lollipop',
86
89
  'line-column': 'Line + column',
90
+ kpi: 'KPI',
87
91
  };
88
92
  function chartTypeLabel(type) {
89
93
  const hit = CORE_CHART_LABELS[type];
@@ -104,21 +108,26 @@ let NileChart = class NileChart extends NileElement {
104
108
  * Usage: `<nile-chart chart-type="pie" />` plus `config.chart` with series data only.
105
109
  */
106
110
  this.chartTypeAttr = '';
107
- /** The summary/insight text displayed in the overlay (fallback when config is not set). */
111
+ /** Summary/insight text shown as the AI panel's opening message when the chat is opened. */
112
+ /**
113
+ * When set, fills `chart.type` if the config omits it (same values as `chart.type`, e.g. `stacked`, `pie`).
114
+ * Usage: `<nile-chart chart-type="pie" />` plus `config.chart` with series data only.
115
+ */
116
+ /** Summary/insight text — shown as the AI panel's opening message when the chat is opened. */
108
117
  this.summary = '';
109
- /** Label for the toggle button (fallback when config is not set). */
110
- this.toggleLabel = 'Summary';
111
- /** Whether the insight overlay is visible. */
112
- this.open = false;
113
118
  this.activeType = null;
114
119
  this.activeConfig = null;
115
120
  this.menuOpen = false;
116
121
  this.chatOpen = false;
122
+ /** True when elements are projected into the `header` slot (default title/subtitle hidden). */
123
+ this.hasHeaderSlotContent = false;
124
+ /** True when elements are projected into `header-actions` (used to show the header row). */
125
+ this.hasHeaderActionsSlot = false;
117
126
  this.handleOutsideClick = (e) => {
118
127
  if (!this.contains(e.target)) {
119
- this.open = false;
120
128
  this.menuOpen = false;
121
- this.emit('nile-chart-toggle', { open: this.open });
129
+ this.chatOpen = false;
130
+ this.chatOpen = false;
122
131
  }
123
132
  };
124
133
  this.resolvedConfig = null;
@@ -126,11 +135,11 @@ let NileChart = class NileChart extends NileElement {
126
135
  get effectiveSummary() {
127
136
  return this.resolvedConfig?.summary ?? this.summary;
128
137
  }
129
- get effectiveToggleLabel() {
130
- return this.resolvedConfig?.toggleLabel ?? this.toggleLabel;
131
- }
138
+ /** AI panel shows when ai.enabled is true OR when a summary is provided. */
139
+ /** AI panel shows when ai.enabled is true OR when a summary is provided. */
132
140
  get aiEnabled() {
133
- return this.resolvedConfig?.ai?.enabled === true;
141
+ return this.resolvedConfig?.ai?.enabled === true || !!this.effectiveSummary;
142
+ return this.resolvedConfig?.ai?.enabled === true || !!this.effectiveSummary;
134
143
  }
135
144
  connectedCallback() {
136
145
  super.connectedCallback();
@@ -169,13 +178,6 @@ let NileChart = class NileChart extends NileElement {
169
178
  this.activeConfig = this.resolvedConfig;
170
179
  }
171
180
  }
172
- toggle(e) {
173
- e.stopPropagation();
174
- this.open = !this.open;
175
- if (this.open)
176
- this.chatOpen = false;
177
- this.emit('nile-chart-toggle', { open: this.open });
178
- }
179
181
  toggleMenu(e) {
180
182
  e.stopPropagation();
181
183
  this.menuOpen = !this.menuOpen;
@@ -183,8 +185,6 @@ let NileChart = class NileChart extends NileElement {
183
185
  toggleChat(e) {
184
186
  e.stopPropagation();
185
187
  this.chatOpen = !this.chatOpen;
186
- if (this.chatOpen)
187
- this.open = false;
188
188
  this.emit('nile-chart-ai-toggle', { open: this.chatOpen });
189
189
  }
190
190
  /** Push an AI response into the chat panel. Call this from your AI handler. */
@@ -220,6 +220,62 @@ let NileChart = class NileChart extends NileElement {
220
220
  get headerSubtitle() {
221
221
  return this.activeConfig?.chartSubtitle ?? this.resolvedConfig?.chartSubtitle ?? '';
222
222
  }
223
+ onHeaderSlotChange(e) {
224
+ const slot = e.target;
225
+ this.hasHeaderSlotContent = slot.assignedElements({ flatten: true }).length > 0;
226
+ this.requestUpdate();
227
+ }
228
+ onHeaderActionsSlotChange(e) {
229
+ const slot = e.target;
230
+ this.hasHeaderActionsSlot = slot.assignedElements({ flatten: true }).length > 0;
231
+ this.requestUpdate();
232
+ }
233
+ syncHeaderSlots() {
234
+ const root = this.shadowRoot;
235
+ if (!root)
236
+ return;
237
+ const headerSlot = root.querySelector('slot[name="header"]');
238
+ const actionsSlot = root.querySelector('slot[name="header-actions"]');
239
+ let changed = false;
240
+ if (headerSlot) {
241
+ const next = headerSlot.assignedElements({ flatten: true }).length > 0;
242
+ if (next !== this.hasHeaderSlotContent) {
243
+ this.hasHeaderSlotContent = next;
244
+ changed = true;
245
+ }
246
+ }
247
+ if (actionsSlot) {
248
+ const next = actionsSlot.assignedElements({ flatten: true }).length > 0;
249
+ if (next !== this.hasHeaderActionsSlot) {
250
+ this.hasHeaderActionsSlot = next;
251
+ changed = true;
252
+ }
253
+ }
254
+ if (changed)
255
+ this.requestUpdate();
256
+ }
257
+ firstUpdated(changedProperties) {
258
+ super.firstUpdated(changedProperties);
259
+ this.syncHeaderSlots();
260
+ }
261
+ /** Direct children with `slot=` — header row renders on first paint before slot assignment runs. */
262
+ lightDomHasSlot(name) {
263
+ for (let i = 0; i < this.children.length; i++) {
264
+ if (this.children[i].getAttribute('slot') === name)
265
+ return true;
266
+ }
267
+ return false;
268
+ }
269
+ shouldShowHeader() {
270
+ const hasTitles = !!(this.headerTitle || this.headerSubtitle);
271
+ const hasBuiltinActions = this.aiEnabled || (this.resolvedConfig?.switchableTypes?.length ?? 0) > 0;
272
+ return (hasTitles ||
273
+ this.hasHeaderSlotContent ||
274
+ this.hasHeaderActionsSlot ||
275
+ this.lightDomHasSlot('header') ||
276
+ this.lightDomHasSlot('header-actions') ||
277
+ hasBuiltinActions);
278
+ }
223
279
  renderTypeSwitcher() {
224
280
  const types = this.resolvedConfig?.switchableTypes;
225
281
  if (!types || types.length === 0)
@@ -268,19 +324,24 @@ let NileChart = class NileChart extends NileElement {
268
324
  `;
269
325
  }
270
326
  renderHeader() {
327
+ if (!this.shouldShowHeader())
328
+ return nothing;
271
329
  const title = this.headerTitle;
272
330
  const subtitle = this.headerSubtitle;
273
- const hasTypeSwitcher = (this.resolvedConfig?.switchableTypes?.length ?? 0) > 0;
274
- const hasActions = hasTypeSwitcher || this.aiEnabled;
275
- if (!title && !subtitle && !hasActions)
276
- return nothing;
331
+ const showDefaultTitles = !this.hasHeaderSlotContent && !!(title || subtitle);
277
332
  return html `
278
333
  <div class="chart-header">
279
334
  <div class="chart-header-titles">
280
- ${title ? html `<h3 class="chart-header-title">${title}</h3>` : nothing}
281
- ${subtitle ? html `<p class="chart-header-subtitle">${subtitle}</p>` : nothing}
335
+ <slot name="header" @slotchange=${this.onHeaderSlotChange}></slot>
336
+ ${showDefaultTitles
337
+ ? html `
338
+ ${title ? html `<h3 class="chart-header-title">${title}</h3>` : nothing}
339
+ ${subtitle ? html `<p class="chart-header-subtitle">${subtitle}</p>` : nothing}
340
+ `
341
+ : nothing}
282
342
  </div>
283
343
  <div class="chart-header-actions">
344
+ <slot name="header-actions" @slotchange=${this.onHeaderActionsSlotChange}></slot>
284
345
  ${this.renderAiTrigger()}
285
346
  ${this.renderTypeSwitcher()}
286
347
  </div>
@@ -290,12 +351,19 @@ let NileChart = class NileChart extends NileElement {
290
351
  renderAiPanel() {
291
352
  if (!this.aiEnabled)
292
353
  return nothing;
293
- const aiConfig = this.resolvedConfig.ai;
354
+ const aiConfig = this.resolvedConfig?.ai;
355
+ const summary = this.effectiveSummary;
356
+ // Summary always takes priority. When summary is present it is the only
357
+ // opening message (shown in blue). welcomeMessage is only used when there
358
+ // is no summary at all.
359
+ const summaryMessage = summary;
360
+ const welcomeMessage = summary ? '' : (aiConfig?.welcomeMessage ?? '');
294
361
  return html `
295
362
  <div class="ai-panel-overlay" ?data-open=${this.chatOpen}>
296
363
  <nile-ai-panel
297
- .placeholder=${aiConfig.placeholder ?? 'Ask about this chart...'}
298
- .welcomeMessage=${aiConfig.welcomeMessage ?? ''}
364
+ .placeholder=${aiConfig?.placeholder ?? 'Ask about this chart...'}
365
+ .welcomeMessage=${welcomeMessage}
366
+ .summaryMessage=${summaryMessage}
299
367
  @nile-ai-send=${this.handleAiSend}
300
368
  ></nile-ai-panel>
301
369
  </div>
@@ -381,6 +449,7 @@ let NileChart = class NileChart extends NileElement {
381
449
  .height=${config.height ?? '400px'}
382
450
  .innerSize=${config.innerSize ?? '50%'}
383
451
  .semiCircle=${config.semiCircle ?? false}
452
+ .semiCircle=${config.semiCircle ?? false}
384
453
  .showDataLabels=${config.showDataLabels ?? true}
385
454
  .showLegend=${config.showLegend ?? true}
386
455
  .options=${mergedOptions}
@@ -441,6 +510,17 @@ let NileChart = class NileChart extends NileElement {
441
510
  .options=${mergedOptions}
442
511
  .loading=${config.loading ?? false}
443
512
  ></nile-waterfall-chart>`;
513
+ case 'map':
514
+ return html `<nile-map-chart
515
+ .data=${config.data}
516
+ .mapData=${config.mapData ?? null}
517
+ .joinBy=${config.joinBy ?? ['hc-key', 'hc-key']}
518
+ .seriesType=${config.seriesType ?? 'map'}
519
+ .zoom=${config.zoom ?? true}
520
+ .height=${config.height ?? '500px'}
521
+ .options=${mergedOptions}
522
+ .loading=${config.loading ?? false}
523
+ ></nile-map-chart>`;
444
524
  case 'stacked':
445
525
  return html `<nile-stacked-chart
446
526
  .data=${config.data}
@@ -768,6 +848,37 @@ let NileChart = class NileChart extends NileElement {
768
848
  .options=${mergedOptions}
769
849
  .loading=${config.loading ?? false}
770
850
  ></nile-xrange-chart>`;
851
+ case 'kpi': {
852
+ const k = config;
853
+ return html `<nile-kpi-chart
854
+ .config=${{
855
+ chart: {
856
+ type: 'kpi',
857
+ variant: k.variant,
858
+ label: k.label,
859
+ value: k.value,
860
+ prefix: k.prefix,
861
+ suffix: k.suffix,
862
+ trendValue: k.trendValue,
863
+ trendDirection: k.trendDirection,
864
+ trendLabel: k.trendLabel,
865
+ description: k.description,
866
+ sparkline: k.sparkline,
867
+ sparklineColor: k.sparklineColor,
868
+ gaugeValue: k.gaugeValue,
869
+ gaugeMin: k.gaugeMin,
870
+ gaugeMax: k.gaugeMax,
871
+ gaugeColor: k.gaugeColor,
872
+ loading: k.loading,
873
+ options: k.options,
874
+ height: k.height,
875
+ },
876
+ aq: {
877
+ chartSubtitle: k.chartSubtitle,
878
+ },
879
+ }}
880
+ ></nile-kpi-chart>`;
881
+ }
771
882
  default: {
772
883
  const _exhaustive = config;
773
884
  return _exhaustive;
@@ -781,23 +892,11 @@ let NileChart = class NileChart extends NileElement {
781
892
  <div class="chart-wrapper">
782
893
  <div class="chart-inner">
783
894
  ${this.activeConfig ? this.renderChartContent() : html `<slot></slot>`}
784
- <button
785
- class="chart-toggle"
786
- aria-expanded="${this.open}"
787
- @click="${this.toggle}"
788
- >
789
- ${this.effectiveToggleLabel}
790
- </button>
791
- <div class="chart-overlay" ?data-open="${this.open}">
792
- <div class="chart-content">
793
- ${this.resolvedConfig
794
- ? this.effectiveSummary
795
- : html `<slot name="insight">${this.summary}</slot>`}
796
- </div>
797
- </div>
798
895
  ${this.renderAiPanel()}
799
896
  </div>
800
897
  </div>
898
+ <slot name="footer"></slot>
899
+ <slot name="footer"></slot>
801
900
  </div>
802
901
  `;
803
902
  }
@@ -812,12 +911,6 @@ __decorate([
812
911
  __decorate([
813
912
  property({ type: String })
814
913
  ], NileChart.prototype, "summary", void 0);
815
- __decorate([
816
- property({ type: String, attribute: 'toggle-label' })
817
- ], NileChart.prototype, "toggleLabel", void 0);
818
- __decorate([
819
- state()
820
- ], NileChart.prototype, "open", void 0);
821
914
  __decorate([
822
915
  state()
823
916
  ], NileChart.prototype, "activeType", void 0);
@@ -830,6 +923,12 @@ __decorate([
830
923
  __decorate([
831
924
  state()
832
925
  ], NileChart.prototype, "chatOpen", void 0);
926
+ __decorate([
927
+ state()
928
+ ], NileChart.prototype, "hasHeaderSlotContent", void 0);
929
+ __decorate([
930
+ state()
931
+ ], NileChart.prototype, "hasHeaderActionsSlot", void 0);
833
932
  __decorate([
834
933
  query('nile-ai-panel')
835
934
  ], NileChart.prototype, "aiPanel", void 0);
@@ -0,0 +1,2 @@
1
+ export { NileDashboardViewer } from './nile-dashboard-viewer.js';
2
+ export type { NileDashboardConfig } from '../internal/types/dashboard-config.type.js';
@@ -0,0 +1,2 @@
1
+ export { NileDashboardViewer } from './nile-dashboard-viewer.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ export declare const styles: import("lit").CSSResult;
@@ -0,0 +1,29 @@
1
+ import { css } from 'lit';
2
+ export const styles = css `
3
+ :host {
4
+ display: block;
5
+ width: 100%;
6
+ }
7
+
8
+ :host([hidden]) {
9
+ display: none;
10
+ }
11
+
12
+ .dashboard-grid {
13
+ display: grid;
14
+ width: 100%;
15
+ }
16
+
17
+ .dashboard-cell {
18
+ overflow: hidden;
19
+ min-height: 0;
20
+ min-width: 0;
21
+ }
22
+
23
+ nile-widget-viewer {
24
+ display: block;
25
+ width: 100%;
26
+ height: 100%;
27
+ }
28
+ `;
29
+ //# sourceMappingURL=nile-dashboard-viewer.css.js.map
@@ -0,0 +1,43 @@
1
+ import { nothing } from 'lit';
2
+ import type { CSSResultGroup, TemplateResult } from 'lit';
3
+ import NileElement from '../internal/nile-element.js';
4
+ import type { NileDashboardConfig } from '../internal/types/dashboard-config.type.js';
5
+ import '../nile-widget-viewer/index.js';
6
+ /**
7
+ * Renders a full dashboard grid of widgets. Each widget is positioned using CSS Grid
8
+ * with the `layout: { x, y, w, h }` values from its config.
9
+ *
10
+ * - `x` / `w` → `grid-column: (x+1) / span w`
11
+ * - `y` / `h` → `grid-row: (y+1) / span h`
12
+ *
13
+ * @example
14
+ * ```html
15
+ * <nile-dashboard-viewer columns="12" cell-height="80" gap="8"></nile-dashboard-viewer>
16
+ * ```
17
+ * ```js
18
+ * el.config = {
19
+ * name: 'My Dashboard',
20
+ * widgets: [
21
+ * { type: 'chart', layout: { x: 0, y: 0, w: 6, h: 4 }, nileConfig: { chart: { type: 'pie', data: [...] } } },
22
+ * { type: 'kpi', layout: { x: 0, y: 4, w: 3, h: 2 }, nileConfig: { chart: { type: 'kpi', label: 'Revenue', value: '$1.2M' } } },
23
+ * ]
24
+ * };
25
+ * ```
26
+ */
27
+ export declare class NileDashboardViewer extends NileElement {
28
+ static styles: CSSResultGroup;
29
+ /** Dashboard configuration containing all widget configs. */
30
+ config: NileDashboardConfig | null;
31
+ /** Total number of grid columns. Default: 12. */
32
+ columns: number;
33
+ /** Height of a single grid row in pixels. Default: 80. */
34
+ cellHeight: number;
35
+ /** Gap between grid cells in pixels. Default: 8. */
36
+ gap: number;
37
+ render(): TemplateResult | typeof nothing;
38
+ }
39
+ declare global {
40
+ interface HTMLElementTagNameMap {
41
+ 'nile-dashboard-viewer': NileDashboardViewer;
42
+ }
43
+ }
@@ -0,0 +1,84 @@
1
+ import { __decorate } from "tslib";
2
+ import { customElement, property } from 'lit/decorators.js';
3
+ import { html, nothing } from 'lit';
4
+ import NileElement from '../internal/nile-element.js';
5
+ import { styles } from './nile-dashboard-viewer.css.js';
6
+ import '../nile-widget-viewer/index.js';
7
+ /**
8
+ * Renders a full dashboard grid of widgets. Each widget is positioned using CSS Grid
9
+ * with the `layout: { x, y, w, h }` values from its config.
10
+ *
11
+ * - `x` / `w` → `grid-column: (x+1) / span w`
12
+ * - `y` / `h` → `grid-row: (y+1) / span h`
13
+ *
14
+ * @example
15
+ * ```html
16
+ * <nile-dashboard-viewer columns="12" cell-height="80" gap="8"></nile-dashboard-viewer>
17
+ * ```
18
+ * ```js
19
+ * el.config = {
20
+ * name: 'My Dashboard',
21
+ * widgets: [
22
+ * { type: 'chart', layout: { x: 0, y: 0, w: 6, h: 4 }, nileConfig: { chart: { type: 'pie', data: [...] } } },
23
+ * { type: 'kpi', layout: { x: 0, y: 4, w: 3, h: 2 }, nileConfig: { chart: { type: 'kpi', label: 'Revenue', value: '$1.2M' } } },
24
+ * ]
25
+ * };
26
+ * ```
27
+ */
28
+ let NileDashboardViewer = class NileDashboardViewer extends NileElement {
29
+ constructor() {
30
+ super(...arguments);
31
+ /** Dashboard configuration containing all widget configs. */
32
+ this.config = null;
33
+ /** Total number of grid columns. Default: 12. */
34
+ this.columns = 12;
35
+ /** Height of a single grid row in pixels. Default: 80. */
36
+ this.cellHeight = 80;
37
+ /** Gap between grid cells in pixels. Default: 8. */
38
+ this.gap = 8;
39
+ }
40
+ render() {
41
+ if (!this.config?.widgets?.length)
42
+ return nothing;
43
+ return html `
44
+ <div
45
+ class="dashboard-grid"
46
+ style="
47
+ grid-template-columns: repeat(${this.columns}, 1fr);
48
+ grid-auto-rows: ${this.cellHeight}px;
49
+ gap: ${this.gap}px;
50
+ "
51
+ >
52
+ ${this.config.widgets.map((widget) => html `
53
+ <div
54
+ class="dashboard-cell"
55
+ style="
56
+ grid-column: ${widget.layout.x + 1} / span ${widget.layout.w};
57
+ grid-row: ${widget.layout.y + 1} / span ${widget.layout.h};
58
+ "
59
+ >
60
+ <nile-widget-viewer .config=${widget}></nile-widget-viewer>
61
+ </div>
62
+ `)}
63
+ </div>
64
+ `;
65
+ }
66
+ };
67
+ NileDashboardViewer.styles = styles;
68
+ __decorate([
69
+ property({ type: Object })
70
+ ], NileDashboardViewer.prototype, "config", void 0);
71
+ __decorate([
72
+ property({ type: Number })
73
+ ], NileDashboardViewer.prototype, "columns", void 0);
74
+ __decorate([
75
+ property({ type: Number, attribute: 'cell-height' })
76
+ ], NileDashboardViewer.prototype, "cellHeight", void 0);
77
+ __decorate([
78
+ property({ type: Number })
79
+ ], NileDashboardViewer.prototype, "gap", void 0);
80
+ NileDashboardViewer = __decorate([
81
+ customElement('nile-dashboard-viewer')
82
+ ], NileDashboardViewer);
83
+ export { NileDashboardViewer };
84
+ //# sourceMappingURL=nile-dashboard-viewer.js.map