@aquera/nile-visualization 2.9.14 → 2.9.16

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/README.md ADDED
@@ -0,0 +1,169 @@
1
+ # \<nile-visualization>
2
+
3
+ This webcomponent follows the [open-wc](https://github.com/open-wc/open-wc) recommendation.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm i @aquera/nile-visualization
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```html
14
+ <script type="module">
15
+ import '@aquera/nile-visualization/nile-bar-chart';
16
+ </script>
17
+
18
+ <nile-bar-chart></nile-bar-chart>
19
+ ```
20
+
21
+ ## Tooling configs
22
+
23
+ For most of the tools, the configuration is in the `package.json` to reduce the amount of files in your project.
24
+
25
+ If you customize the configuration a lot, you can consider moving them to individual files.
26
+
27
+ ## Local Demo with `web-dev-server`
28
+
29
+ ```bash
30
+ npm start
31
+ ```
32
+
33
+ To run a local development server that serves the basic demo located in `demo/index.html`
34
+
35
+ ## Release Notes
36
+
37
+ In this section, you can find the updates for each release of `nile-visualization`. It's a good practice to maintain detailed release notes to help users and developers understand what changes have been made from one version to another and how these changes might affect their projects.
38
+
39
+ #### Version 2.9.16 (June 03, 2026)
40
+ - Nile Chart: Added Portal Property in Menu. (UIF-1253)
41
+
42
+ #### Version 2.9.15 (June 02, 2026)
43
+ - Nile Filter Chart: Filter chip fixes (UIF-1250)
44
+
45
+ #### Version 2.9.14 (May 29, 2026)
46
+ - Nile Chart: Fixes and improvements
47
+
48
+ #### Version 2.9.13 (May 29, 2026)
49
+ - Nile Chart: Fixes and improvements
50
+ - Nile Filter Chart: Fixes and improvements
51
+
52
+ #### Version 2.9.12 (May 26, 2026)
53
+ - Nile Chart: Fixes and improvements
54
+
55
+ #### Version 2.9.11 (May 21, 2026)
56
+ - Nile Chart: Fixes and improvements
57
+ - Nile KPI Chart: Fixes and improvements
58
+
59
+ #### Version 2.9.10 (May 20, 2026)
60
+ - Nile Chart: Fixes and improvements
61
+ - Nile Filter Chart: Fixes and improvements
62
+
63
+ #### Version 2.9.9 (May 19, 2026)
64
+ - Nile Chart: Fixes and improvements
65
+ - Nile Filter Chart: Fixes and improvements
66
+
67
+ #### Version 2.9.7 (May 13, 2026)
68
+ - Nile KPI Chart: Fixes and improvements
69
+
70
+ #### Version 2.9.6 (May 12, 2026)
71
+ - Nile Filter Chart: Fixes and improvements
72
+
73
+ #### Version 2.9.5 (May 11, 2026)
74
+ - Nile Chart: Fixes and improvements
75
+ - Nile Filter Chart: Fixes and improvements
76
+
77
+ #### Version 2.9.4 (May 11, 2026)
78
+ - Nile KPI Chart: Fixes and improvements
79
+
80
+ #### Version 2.9.3 (May 09, 2026)
81
+ - Nile Chart: Fixes and improvements
82
+ - Nile Filter Chart: Fixes and improvements
83
+
84
+ #### Version 2.9.2 (May 07, 2026)
85
+ - Nile Chart: Fixes and improvements
86
+ - Nile KPI Chart: Fixes and improvements
87
+
88
+ #### Version 2.8.0 (May 04, 2026)
89
+ - Internal and type updates
90
+
91
+ #### Version 2.7.0 (May 04, 2026)
92
+ - Nile Filter Chart: Updates and improvements
93
+
94
+ #### Version 2.6.0 (April 30, 2026)
95
+ - Dependency and build updates
96
+
97
+ #### Version 2.3.0 (April 28, 2026)
98
+ - Nile Filter Chart: Added New Component
99
+ - Nile Chart: Updates and improvements
100
+
101
+ #### Version 2.2.0 (April 24, 2026)
102
+ - Nile Chart: Updates and improvements
103
+
104
+ #### Version 2.1.0 (April 23, 2026)
105
+ - Updates across all chart components
106
+
107
+ #### Version 1.9.0 (April 22, 2026)
108
+ - Nile Chart: Updates and improvements
109
+ - Nile KPI Chart: Updates and improvements
110
+ - Internal and type updates
111
+
112
+ #### Version 1.6.0 (April 21, 2026)
113
+ - Updates across all chart components and internals
114
+
115
+ #### Version 1.4.0 (April 20, 2026)
116
+ - Nile Chart: Updates and improvements
117
+
118
+ #### Version 1.3.0 (April 17, 2026)
119
+ - Nile Chart: Updates and improvements
120
+ - Internal updates
121
+
122
+ #### Version 1.2.0 (April 17, 2026)
123
+ - Nile Executive Summary: Updates and improvements
124
+
125
+ #### Version 1.1.0 (April 17, 2026)
126
+ - Nile Executive Summary: Updates and improvements
127
+
128
+ #### Version 1.0.0 (April 17, 2026)
129
+ - First stable release
130
+ - Nile Chart: Updates and improvements
131
+
132
+ #### Version 0.9.0 (April 16, 2026)
133
+ - Nile AI Panel: Updates and improvements
134
+ - Nile Dashboard Viewer: Updates and improvements
135
+
136
+ #### Version 0.8.0 (April 16, 2026)
137
+ - Nile Executive Summary: Added New Component
138
+ - Nile Chart: Updates and improvements
139
+ - Nile KPI Chart: Updates and improvements
140
+
141
+ #### Version 0.7.0 (April 15, 2026)
142
+ - Nile Chart: Updates and improvements
143
+ - Nile KPI Chart: Updates and improvements
144
+
145
+ #### Version 0.6.0 (April 15, 2026)
146
+ - Nile Widget Viewer: Added New Component
147
+ - Nile Dashboard Viewer: Added New Component
148
+
149
+ #### Version 0.5.0 (April 14, 2026)
150
+ - Nile KPI Chart: Added New Component with KPI configuration
151
+ - Nile AI Panel: Updates and improvements
152
+ - Nile Chart: Updates and improvements
153
+
154
+ #### Version 0.4.0 (April 14, 2026)
155
+ - Nile Heatmap Chart: Added New Component
156
+ - Nile Line Column Chart: Added New Component
157
+ - Nile Organization Chart: Added New Component
158
+ - Nile Bellcurve Chart, Nile Donut Chart, Nile Histogram Chart: Updates and improvements
159
+
160
+ #### Version 0.3.0 (April 13, 2026)
161
+ - Added chart variants: Nile Area Negative Chart, Nile Area Range Chart, Nile Area Spline Chart, Nile Column Drilldown Chart, Nile Column Pyramid Chart, Nile Column Range Chart, Nile Dumbbell Lower Chart, Nile Dumbbell Upper Chart, Nile Euler Chart, Nile Inverted Area Chart, Nile Lollipop Chart, Nile Polygon Chart, Nile Radial Bar Chart, Nile Variable Pie Chart, Nile Vector Chart, Nile XRange Chart
162
+
163
+ #### Version 0.2.0 (April 10, 2026)
164
+ - Expanded the chart catalog: Nile Anomaly Chart, Nile Area Chart, Nile Bar Chart, Nile Bellcurve Chart, Nile Boxplot Chart, Nile Bubble Chart, Nile Cluster Chart, Nile Column Chart, Nile Donut Chart, Nile Dumbbell Chart, Nile Fan Chart, Nile Flame Chart, Nile Funnel Chart, Nile Gauge Chart, Nile Histogram Chart, and more
165
+ - Nile AI Panel: Added New Component
166
+ - Nile AI Sender: Added New Component
167
+
168
+ #### Version 0.1.0 (April 09, 2026)
169
+ - Initial release of the Nile Visualization package
@@ -1,2 +1,3 @@
1
1
  export declare const tooltipCss = "\n .nile-chart-header-tooltip {\n position: fixed;\n display: none;\n transform: translate(-50%, calc(-100% - 10px));\n background: var(--nile-colors-white-base, var(--ng-colors-bg-primary));\n color: var(--nile-colors-dark-900, var(--ng-colors-text-primary-900));\n font-family: var(--nile-font-family-serif, var(--ng-font-family-body));\n font-size: var(--nile-type-scale-2, var(--ng-font-size-text-xs));\n font-weight: var(--nile-font-weight-medium, var(--ng-font-weight-medium));\n line-height: 1.4;\n padding: 4px 10px;\n border-radius: 6px;\n border: 1px solid var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));\n pointer-events: none;\n white-space: nowrap;\n z-index: 2147483647;\n box-shadow: var(--nile-box-shadow-3, var(--ng-shadow-sm));\n }\n .nile-chart-header-tooltip::after {\n content: '';\n position: absolute;\n top: 100%;\n left: 50%;\n transform: translateX(-50%);\n border: 5px solid transparent;\n border-top-color: var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));\n }\n";
2
+ export declare function injectGlobalChartMenuOverrides(): void;
2
3
  export declare const styles: import("lit").CSSResult;
@@ -28,6 +28,58 @@ export const tooltipCss = `
28
28
  border-top-color: var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));
29
29
  }
30
30
  `;
31
+ const MENU_OVERRIDE_CSS = `
32
+ nile-menu.nile-chart-actions-menu {
33
+ min-width: var(--nile-width-140px, var(--ng-height-140px, 140px));
34
+ }
35
+
36
+ nile-menu.nile-chart-actions-menu nile-menu-item.nile-chart-actions-menu-item::part(base) {
37
+ font-family: var(--nile-font-family-serif, var(--ng-font-family-body));
38
+ font-size: var(--nile-type-scale-3, var(--ng-font-size-text-sm));
39
+ font-weight: var(--nile-font-weight-medium, var(--ng-font-weight-medium));
40
+ color: var(--nile-colors-dark-900, var(--ng-colors-text-primary-900));
41
+ }
42
+
43
+ nile-menu.nile-chart-actions-menu nile-menu-item.nile-chart-actions-menu-item[active]::part(label) {
44
+ color: var(--nile-colors-primary-600, var(--ng-colors-fg-brand-primary-600));
45
+ font-weight: 600;
46
+ }
47
+
48
+ nile-menu.nile-chart-actions-menu .nile-chart-actions-menu-glyph {
49
+ flex-shrink: 0;
50
+ display: inline-flex;
51
+ color: var(--nile-colors-neutral-700, var(--ng-colors-text-quaternary-500));
52
+ }
53
+
54
+ nile-menu.nile-chart-actions-menu .nile-chart-actions-menu-separator {
55
+ height: var(--nile-border-width-1, var(--ng-stroke-width-1, 1px));
56
+ background: var(--nile-colors-neutral-200, var(--ng-colors-border-secondary));
57
+ margin: var(--nile-spacing-md, var(--ng-spacing-md, 8px));
58
+ }
59
+
60
+ nile-menu.nile-chart-actions-menu .nile-chart-actions-menu-group-header {
61
+ display: block;
62
+ padding: var(--nile-spacing-md, var(--ng-spacing-md, 8px)) var(--nile-spacing-14px, var(--ng-spacing-3-5, 14px)) var(--nile-spacing-xs, var(--ng-spacing-xs, 4px));
63
+ font-family: var(--nile-font-family-serif, var(--ng-font-family-body));
64
+ font-size: var(--nile-type-scale-3, var(--ng-font-size-text-sm));
65
+ font-weight: var(--nile-font-weight-medium, var(--ng-font-weight-medium));
66
+ color: var(--nile-colors-neutral-500, var(--ng-colors-text-tertiary-600));
67
+ pointer-events: none;
68
+ user-select: none;
69
+ }
70
+ `;
71
+ export function injectGlobalChartMenuOverrides() {
72
+ if (typeof document === 'undefined')
73
+ return;
74
+ const STYLE_ID = 'nile-chart-actions-menu-overrides';
75
+ if (document.getElementById(STYLE_ID))
76
+ return;
77
+ const style = document.createElement('style');
78
+ style.id = STYLE_ID;
79
+ style.textContent = MENU_OVERRIDE_CSS;
80
+ document.head?.appendChild(style);
81
+ }
82
+ injectGlobalChartMenuOverrides();
31
83
  export const styles = css `
32
84
  :host {
33
85
  display: block;
@@ -321,7 +373,7 @@ export const styles = css `
321
373
  /* ── Actions Menu (in header) ── */
322
374
 
323
375
  .nile-chart-menu-anchor {
324
- position: relative;
376
+ display: inline-flex;
325
377
  }
326
378
 
327
379
  .nile-chart-menu-trigger {
@@ -349,76 +401,7 @@ export const styles = css `
349
401
  outline-offset: var(--nile-spacing-1px, var(--ng-outline-offset-1));
350
402
  }
351
403
 
352
- .nile-chart-menu-dropdown {
353
- position: absolute;
354
- top: 100%;
355
- right: 0;
356
- margin-top: var(--nile-spacing-xs, var(--ng-spacing-xs));
357
- min-width: var(--nile-width-140px, var(--ng-height-140px));
358
- background: var(--nile-colors-white-base, var(--ng-colors-bg-primary));
359
- border: var(--nile-border-width-1, var(--ng-stroke-width-1)) solid var(--nile-colors-neutral-400, var(--ng-colors-border-secondary));
360
- border-radius: var(--nile-radius-radius-xl, var(--ng-radius-md));
361
- box-shadow: var(--nile-box-shadow-7, var(--ng-shadow-md));
362
- padding: var(--nile-spacing-xs, var(--ng-spacing-xs)) 0;
363
- overflow: hidden;
364
- z-index: 10;
365
- }
366
-
367
- .nile-chart-menu-item {
368
- display: flex;
369
- align-items: center;
370
- gap: var(--nile-spacing-6px, var(--ng-spacing-sm));
371
- width: 100%;
372
- padding: var(--nile-spacing-md, var(--ng-spacing-md)) var(--nile-spacing-14px, var(--ng-spacing-3-5));
373
- border: none;
374
- background: none;
375
- color: var(--nile-colors-dark-900, var(--ng-colors-text-primary-900));
376
- font-family: var(--nile-font-family-serif, var(--ng-font-family-body));
377
- font-size: var(--nile-type-scale-3, var(--ng-font-size-text-sm));
378
- font-weight: var(--nile-font-weight-medium, var(--ng-font-weight-medium));
379
- text-align: left;
380
- cursor: pointer;
381
- transition: background var(--nile-transition-duration-short, var(--ng-transition-duration-fast)) ease;
382
- }
383
-
384
- .nile-chart-menu-item-glyph {
385
- flex-shrink: 0;
386
- color: var(--nile-colors-neutral-700, var(--ng-colors-text-quaternary-500));
387
- }
388
-
389
- .nile-chart-menu-item:hover {
390
- background: var(--nile-colors-neutral-100, var(--ng-colors-bg-secondary));
391
- color: var(--nile-colors-dark-900, var(--ng-colors-text-primary-900));
392
- }
393
-
394
- .nile-chart-menu-item.active {
395
- color: var(--nile-colors-primary-600, var(--ng-colors-fg-brand-primary-600));
396
- font-weight: 600;
397
- }
398
-
399
- .nile-chart-menu-item:focus-visible {
400
- outline: var(--nile-border-width-2, var(--ng-stroke-width-2)) solid var(--nile-colors-primary-600, var(--ng-colors-fg-brand-primary-600));
401
- outline-offset: calc(var(--nile-spacing-2px, var(--ng-outline-offset-2)) * -1);
402
- }
403
-
404
- .nile-chart-menu-separator {
405
- height: var(--nile-border-width-1, var(--ng-stroke-width-1));
406
- background: var(--nile-colors-neutral-200, var(--ng-colors-border-secondary));
407
- margin: var(--nile-spacing-md, var(--ng-spacing-md));
408
- }
409
-
410
- .nile-chart-menu-group-header {
411
- display: block;
412
- padding: var(--nile-spacing-md, var(--ng-spacing-md)) var(--nile-spacing-14px, var(--ng-spacing-3-5)) var(--nile-spacing-xs, var(--ng-spacing-xs));
413
- font-family: var(--nile-font-family-serif, var(--ng-font-family-body));
414
- font-size: var(--nile-type-scale-3, var(--ng-font-size-text-sm));
415
- font-weight: var(--nile-font-weight-medium, var(--ng-font-weight-medium));
416
- color: var(--nile-colors-neutral-500, var(--ng-colors-text-tertiary-600));
417
- pointer-events: none;
418
- user-select: none;
419
- }
420
-
421
- /* ── AI Chat Trigger (in header) ── */
404
+
422
405
 
423
406
  .nile-ai-trigger {
424
407
  display: inline-flex;
@@ -88,7 +88,6 @@ export declare class NileChart extends NileElement {
88
88
  menu: NileChartMenuConfig | null;
89
89
  private activeType;
90
90
  private activeConfig;
91
- private menuOpen;
92
91
  private chatOpen;
93
92
  private _hcChart;
94
93
  /** True when elements are projected into the `header` slot (default title/subtitle hidden). */
@@ -108,7 +107,7 @@ export declare class NileChart extends NileElement {
108
107
  private resolveConfig;
109
108
  private resolvedConfig;
110
109
  protected updated(changedProperties: PropertyValues): void;
111
- private toggleMenu;
110
+ private closeMenu;
112
111
  private toggleChat;
113
112
  /** Push an AI response into the chat panel. Call this from your AI handler. */
114
113
  addAiResponse(text: string): void;
@@ -2,7 +2,7 @@ import { __decorate } from "tslib";
2
2
  import { customElement, property, query, state } from 'lit/decorators.js';
3
3
  import { html, nothing } from 'lit';
4
4
  import NileElement from '../internal/nile-element.js';
5
- import { styles, tooltipCss } from './nile-chart.css.js';
5
+ import { styles, tooltipCss, injectGlobalChartMenuOverrides } from './nile-chart.css.js';
6
6
  import { nileChartConfig } from './nile-chart-config-builder.js';
7
7
  import { renderChartSkeleton } from './nile-chart-skeleton.js';
8
8
  import { convertConfig } from '../internal/chart-adapters.js';
@@ -158,7 +158,6 @@ let NileChart = class NileChart extends NileElement {
158
158
  this.menu = null;
159
159
  this.activeType = null;
160
160
  this.activeConfig = null;
161
- this.menuOpen = false;
162
161
  this.chatOpen = false;
163
162
  this._hcChart = null;
164
163
  /** True when elements are projected into the `header` slot (default title/subtitle hidden). */
@@ -168,7 +167,6 @@ let NileChart = class NileChart extends NileElement {
168
167
  this.handleOutsideClick = (e) => {
169
168
  const path = e.composedPath();
170
169
  if (!path.includes(this)) {
171
- this.menuOpen = false;
172
170
  this.chatOpen = false;
173
171
  return;
174
172
  }
@@ -210,6 +208,7 @@ let NileChart = class NileChart extends NileElement {
210
208
  connectedCallback() {
211
209
  super.connectedCallback();
212
210
  ensureHeaderTooltipStyles();
211
+ injectGlobalChartMenuOverrides();
213
212
  const tip = document.createElement('div');
214
213
  tip.className = 'nile-chart-header-tooltip';
215
214
  document.body.appendChild(tip);
@@ -262,9 +261,9 @@ let NileChart = class NileChart extends NileElement {
262
261
  this.appearance = resolved.appearance;
263
262
  }
264
263
  }
265
- toggleMenu(e) {
266
- e.stopPropagation();
267
- this.menuOpen = !this.menuOpen;
264
+ closeMenu() {
265
+ const dropdown = this.shadowRoot?.querySelector('.nile-chart-menu-anchor');
266
+ dropdown?.hide?.();
268
267
  }
269
268
  toggleChat(e) {
270
269
  e.stopPropagation();
@@ -291,7 +290,7 @@ let NileChart = class NileChart extends NileElement {
291
290
  const converted = convertConfig(this.resolvedConfig, toType);
292
291
  this.activeType = toType;
293
292
  this.activeConfig = converted;
294
- this.menuOpen = false;
293
+ this.closeMenu();
295
294
  this.emit('nile-chart-type-change', {
296
295
  fromType,
297
296
  toType,
@@ -401,7 +400,7 @@ let NileChart = class NileChart extends NileElement {
401
400
  }
402
401
  }
403
402
  async viewFullscreen() {
404
- this.menuOpen = false;
403
+ this.closeMenu();
405
404
  await this.ensureExporting();
406
405
  if (this._hcChart?.fullscreen?.open) {
407
406
  this._hcChart.fullscreen.open();
@@ -411,25 +410,26 @@ let NileChart = class NileChart extends NileElement {
411
410
  target.requestFullscreen?.();
412
411
  }
413
412
  async printChart() {
414
- this.menuOpen = false;
413
+ this.closeMenu();
415
414
  await this.ensureExporting();
416
415
  this._hcChart?.print?.();
417
416
  }
418
417
  async exportChart(type) {
419
- this.menuOpen = false;
418
+ this.closeMenu();
420
419
  await this.ensureExporting();
421
420
  const filename = (this.headerTitle || 'chart').replace(/[^a-z0-9_-]+/gi, '_');
422
421
  this._hcChart?.exportChartLocal?.({ type, filename, local: true });
423
422
  }
424
423
  async downloadCsv() {
425
- this.menuOpen = false;
424
+ this.closeMenu();
426
425
  await this.ensureExporting();
427
426
  this._hcChart?.downloadCSV?.();
428
427
  }
429
428
  _renderMenuItem(item, hasChart) {
430
429
  const glyph = item.glyph
431
430
  ? html `<nile-glyph
432
- class="nile-chart-menu-item-glyph"
431
+ slot="prefix"
432
+ class="nile-chart-actions-menu-glyph"
433
433
  name=${item.glyph}
434
434
  method=${item.method ?? 'stroke'}
435
435
  color=${item.color ?? 'var(--nile-colors-dark-500,var(--ng-colors-fg-secondary-700))'}
@@ -438,22 +438,22 @@ let NileChart = class NileChart extends NileElement {
438
438
  : nothing;
439
439
  if (item.type === 'custom') {
440
440
  return html `
441
- ${item.divider ? html `<div class="nile-chart-menu-separator"></div>` : nothing}
442
- <button type="button" class="nile-chart-menu-item" role="menuitem"
443
- @click=${() => { this.menuOpen = false; this.emit('nile-menu-change', { id: item.id }); }}>
441
+ ${item.divider ? html `<div class="nile-chart-actions-menu-separator" role="separator"></div>` : nothing}
442
+ <nile-menu-item class="nile-chart-actions-menu-item" value=${`custom:${item.id}`}
443
+ @click=${() => { this.closeMenu(); this.emit('nile-menu-change', { id: item.id }); }}>
444
444
  ${glyph}${item.label}
445
- </button>
445
+ </nile-menu-item>
446
446
  `;
447
447
  }
448
448
  if (!hasChart)
449
449
  return nothing;
450
450
  return html `
451
- ${item.divider ? html `<div class="nile-chart-menu-separator"></div>` : nothing}
452
- ${item.fullscreen ? html `<button type="button" class="nile-chart-menu-item" role="menuitem" @click=${() => this.viewFullscreen()}>${glyph}${item.label ?? 'Fullscreen'}</button>` : nothing}
453
- ${item.print ? html `<button type="button" class="nile-chart-menu-item" role="menuitem" @click=${() => this.printChart()}>${glyph}${item.label ?? 'Print'}</button>` : nothing}
454
- ${item.downloadPng ? html `<button type="button" class="nile-chart-menu-item" role="menuitem" @click=${() => this.exportChart('image/png')}>${glyph}${item.label ?? 'Download PNG'}</button>` : nothing}
455
- ${item.downloadSvg ? html `<button type="button" class="nile-chart-menu-item" role="menuitem" @click=${() => this.exportChart('image/svg+xml')}>${glyph}${item.label ?? 'Download SVG'}</button>` : nothing}
456
- ${item.downloadCsv ? html `<button type="button" class="nile-chart-menu-item" role="menuitem" @click=${() => this.downloadCsv()}>${glyph}${item.label ?? 'Download CSV'}</button>` : nothing}
451
+ ${item.divider ? html `<div class="nile-chart-actions-menu-separator" role="separator"></div>` : nothing}
452
+ ${item.fullscreen ? html `<nile-menu-item class="nile-chart-actions-menu-item" value="fullscreen" @click=${() => this.viewFullscreen()}>${glyph}${item.label ?? 'Fullscreen'}</nile-menu-item>` : nothing}
453
+ ${item.print ? html `<nile-menu-item class="nile-chart-actions-menu-item" value="print" @click=${() => this.printChart()}>${glyph}${item.label ?? 'Print'}</nile-menu-item>` : nothing}
454
+ ${item.downloadPng ? html `<nile-menu-item class="nile-chart-actions-menu-item" value="download-png" @click=${() => this.exportChart('image/png')}>${glyph}${item.label ?? 'Download PNG'}</nile-menu-item>` : nothing}
455
+ ${item.downloadSvg ? html `<nile-menu-item class="nile-chart-actions-menu-item" value="download-svg" @click=${() => this.exportChart('image/svg+xml')}>${glyph}${item.label ?? 'Download SVG'}</nile-menu-item>` : nothing}
456
+ ${item.downloadCsv ? html `<nile-menu-item class="nile-chart-actions-menu-item" value="download-csv" @click=${() => this.downloadCsv()}>${glyph}${item.label ?? 'Download CSV'}</nile-menu-item>` : nothing}
457
457
  `;
458
458
  }
459
459
  renderActionsMenu() {
@@ -469,41 +469,44 @@ let NileChart = class NileChart extends NileElement {
469
469
  ];
470
470
  const hasChart = !!this._hcChart;
471
471
  const hasAnyItems = !!(types?.length || allItems.length);
472
+ if (!hasAnyItems) {
473
+ return html `
474
+ <button type="button" class="nile-chart-menu-trigger" aria-label="Chart actions">
475
+ <nile-glyph name="options" size="16"></nile-glyph>
476
+ </button>
477
+ `;
478
+ }
472
479
  return html `
473
- <div class="nile-chart-menu-anchor">
480
+ <nile-dropdown class="nile-chart-menu-anchor" placement="bottom-end" distance="4" portal>
474
481
  <button
475
482
  type="button"
483
+ slot="trigger"
476
484
  class="nile-chart-menu-trigger"
477
- aria-haspopup="true"
478
- aria-expanded=${this.menuOpen ? 'true' : 'false'}
479
485
  aria-label="Chart actions"
480
- @click=${(e) => this.toggleMenu(e)}
481
486
  >
482
487
  <nile-glyph name="options" size="16"></nile-glyph>
483
488
  </button>
484
- ${this.menuOpen && hasAnyItems ? html `
485
- <div class="nile-chart-menu-dropdown" role="menu">
486
- ${types?.length ? html `
487
- ${types.map(type => html `
488
- <button type="button" class="nile-chart-menu-item ${type === this.activeType ? 'active' : ''}" role="menuitem" @click=${() => this.switchType(type)}>
489
- ${chartTypeLabel(type)}
490
- </button>
491
- `)}
492
- ${allItems.length ? html `<div class="nile-chart-menu-separator"></div>` : nothing}
493
- ` : nothing}
494
- ${allItems.map(item => {
489
+ <nile-menu class="nile-chart-actions-menu" part="dropdown">
490
+ ${types?.length ? html `
491
+ ${types.map(type => html `
492
+ <nile-menu-item class="nile-chart-actions-menu-item" value=${`type:${type}`} ?active=${type === this.activeType} @click=${() => this.switchType(type)}>
493
+ ${chartTypeLabel(type)}
494
+ </nile-menu-item>
495
+ `)}
496
+ ${allItems.length ? html `<div class="nile-chart-actions-menu-separator" role="separator"></div>` : nothing}
497
+ ` : nothing}
498
+ ${allItems.map(item => {
495
499
  if (item.type === 'group') {
496
500
  return html `
497
- ${item.divider ? html `<div class="nile-chart-menu-separator"></div>` : nothing}
498
- <span class="nile-chart-menu-group-header" role="presentation">${item.label}</span>
499
- ${item.items.map(child => this._renderMenuItem(child, hasChart))}
500
- `;
501
+ ${item.divider ? html `<div class="nile-chart-actions-menu-separator" role="separator" part="seperator"></div>` : nothing}
502
+ <span class="nile-chart-actions-menu-group-header" role="presentation" part="header">${item.label}</span>
503
+ ${item.items.map(child => this._renderMenuItem(child, hasChart))}
504
+ `;
501
505
  }
502
506
  return this._renderMenuItem(item, hasChart);
503
507
  })}
504
- </div>
505
- ` : nothing}
506
- </div>
508
+ </nile-menu>
509
+ </nile-dropdown>
507
510
  `;
508
511
  }
509
512
  renderAiTrigger() {
@@ -1805,9 +1808,6 @@ __decorate([
1805
1808
  __decorate([
1806
1809
  state()
1807
1810
  ], NileChart.prototype, "activeConfig", void 0);
1808
- __decorate([
1809
- state()
1810
- ], NileChart.prototype, "menuOpen", void 0);
1811
1811
  __decorate([
1812
1812
  state()
1813
1813
  ], NileChart.prototype, "chatOpen", void 0);
@@ -180,15 +180,6 @@ let NileFilterChart = NileFilterChart_1 = class NileFilterChart extends NileElem
180
180
  if (this.promptFieldWidth.get(id) === rounded)
181
181
  return;
182
182
  this.promptFieldWidth = new Map(this.promptFieldWidth).set(id, rounded);
183
- // Tippy popups are portaled to document.body so component-scoped styles
184
- // can't reach them, and nile-lite-tooltip's `maxWidth` only takes effect
185
- // at attach time (its updated() hook doesn't re-attach for maxWidth
186
- // changes). Mirror the live width onto a document-level CSS variable
187
- // the global .tippy-box rule reads — wrapping then always reflects
188
- // the current input width.
189
- if (typeof document !== 'undefined') {
190
- document.documentElement.style.setProperty('--fc-prompt-tooltip-max-width', `${rounded}px`);
191
- }
192
183
  }
193
184
  _validateOrClear(ctrl, value, opts = {}) {
194
185
  const isNql = this.promptModes.get(ctrl.id) === 'expression';
@@ -276,70 +276,35 @@ function renderModeToggle(host, ctrl, mode) {
276
276
  </nile-button-toggle-group>
277
277
  `;
278
278
  }
279
- const SUGGESTION_LAYOUT_STYLE_ID = 'fc-prompt-suggestion-layout-v4';
280
- function ensureSuggestionLayoutStyles() {
279
+ const PROMPT_TIPPY_STYLE_ID = 'fc-prompt-tippy-styles-v1';
280
+ function ensurePromptTippyStyles() {
281
281
  if (typeof document === 'undefined')
282
282
  return;
283
- if (document.getElementById(SUGGESTION_LAYOUT_STYLE_ID))
283
+ if (document.getElementById(PROMPT_TIPPY_STYLE_ID))
284
284
  return;
285
285
  const el = document.createElement('style');
286
- el.id = SUGGESTION_LAYOUT_STYLE_ID;
286
+ el.id = PROMPT_TIPPY_STYLE_ID;
287
287
  el.textContent = `
288
- .fc-prompt__menu nile-menu-item::part(label) {
289
- flex: 1;
290
- min-width: 0;
291
- overflow: hidden;
292
- }
293
-
294
- .fc-prompt__suggestion-label {
295
- display: block;
296
- max-width: 100%;
297
- overflow: hidden;
298
- text-overflow: ellipsis;
299
- white-space: nowrap;
300
- }
301
-
302
- .fc-prompt__suggestion-tooltip {
303
- display: block;
304
- flex: 1;
305
- min-width: 0;
306
- overflow: hidden;
307
- }
308
-
309
-
310
-
311
- [data-tippy-root] {
288
+ [data-tippy-root].fc-prompt-tippy {
312
289
  max-width: var(--fc-prompt-tooltip-max-width, 320px);
313
290
  }
314
- [data-tippy-root] > .tippy-box,
315
- .tippy-box[data-theme~='lite'] {
291
+ [data-tippy-root].fc-prompt-tippy > .tippy-box {
316
292
  max-width: var(--fc-prompt-tooltip-max-width, 320px);
317
293
  white-space: normal;
318
294
  overflow-wrap: anywhere;
319
295
  word-break: break-word;
320
296
  }
321
- [data-tippy-root] > .tippy-box > .tippy-content {
297
+ [data-tippy-root].fc-prompt-tippy > .tippy-box > .tippy-content {
322
298
  white-space: normal;
323
299
  overflow-wrap: anywhere;
324
300
  word-break: break-word;
325
301
  max-width: 100%;
326
302
  }
327
- .fc-prompt__suggestion-tag {
328
- flex-shrink: 0;
329
- padding: 1px 8px;
330
- border-radius: 999px;
331
- background: var(--nile-colors-neutral-100, var(--ng-colors-bg-secondary));
332
- color: var(--nile-colors-neutral-700, var(--ng-colors-text-quaternary-500));
333
- font-size: 10px;
334
- font-weight: 600;
335
- text-transform: uppercase;
336
- letter-spacing: 0.04em;
337
- }
338
303
  `;
339
304
  document.head.appendChild(el);
340
305
  }
341
306
  export function renderPrompt(host, ctrl) {
342
- ensureSuggestionLayoutStyles();
307
+ ensurePromptTippyStyles();
343
308
  const value = String(host.selectedValues.get(ctrl.id) ?? '');
344
309
  const animated = host.promptPlaceholder.get(ctrl.id) ?? '';
345
310
  const error = host.promptErrors.get(ctrl.id);
@@ -859,6 +824,13 @@ export function renderPrompt(host, ctrl) {
859
824
  content="${item.label}"
860
825
  class="fc-prompt__suggestion-tooltip"
861
826
  .maxWidth=${fieldWidth}
827
+ @nile-show="${(e) => {
828
+ const popper = e.detail?.instance?.popper;
829
+ if (!popper)
830
+ return;
831
+ popper.classList.add('fc-prompt-tippy');
832
+ popper.style.setProperty('--fc-prompt-tooltip-max-width', `${host.promptFieldWidth.get(ctrl.id) ?? 320}px`);
833
+ }}"
862
834
  >
863
835
  <span class="fc-prompt__suggestion-label">${item.label}</span>
864
836
  </nile-lite-tooltip>`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aquera/nile-visualization",
3
- "version": "2.9.14",
3
+ "version": "2.9.16",
4
4
  "description": "A visualization Library for the Nile Design System",
5
5
  "license": "MIT",
6
6
  "author": "Aquera Inc",