@aquera/nile-visualization 1.8.0 → 2.0.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.
@@ -106,6 +106,8 @@ let NileKpiChart = class NileKpiChart extends NileElement {
106
106
  this.cardPaddingVertical = '';
107
107
  this.cardPaddingHorizontal = '';
108
108
  this.contentGap = '';
109
+ /** Accent bar colour for the 'accent' variant. */
110
+ this.accentColor = '';
109
111
  // ── Label ──
110
112
  this.labelColor = '';
111
113
  this.labelFontSize = '';
@@ -124,6 +126,14 @@ let NileKpiChart = class NileKpiChart extends NileElement {
124
126
  this.loading = false;
125
127
  /** Highcharts options override for the sparkline or gauge. */
126
128
  this.options = {};
129
+ /** How to abbreviate the numeric value. 'auto' picks K/M/B/T by magnitude. Default: 'auto'. */
130
+ this.valueFormat = 'auto';
131
+ /** Base unit combined with the magnitude prefix (e.g. 'L' → "1.5KL"). */
132
+ this.unit = '';
133
+ /** Decimal places for the abbreviated value. null = auto (0–2 by magnitude). */
134
+ this.precision = null;
135
+ /** BCP 47 locale for number formatting, e.g. 'en-IN'. Defaults to browser locale. */
136
+ this.locale = '';
127
137
  /**
128
138
  * Set by nile-chart: skip host border/shadow (variant card/gauge) so the parent chart-card is the only frame.
129
139
  */
@@ -160,7 +170,25 @@ let NileKpiChart = class NileKpiChart extends NileElement {
160
170
  // ── Value / Gauge hover handlers ─────────────────────────────────────────
161
171
  this._onValueEnter = (e) => {
162
172
  const rect = e.currentTarget.getBoundingClientRect();
163
- this._showTip(this.getTooltipContent(), rect.left + rect.width / 2, rect.top);
173
+ const rawNum = this.parseNumericValue(this.value);
174
+ const full = rawNum != null ? this.formatValue(rawNum).full : String(this.value ?? '');
175
+ const prefix = this.prefix ?? '';
176
+ const suffix = this.suffix ?? '';
177
+ this._showTip(`${prefix}${full}${suffix}`.trim(), rect.left + rect.width / 2, rect.top);
178
+ };
179
+ this._onDescEnter = (e) => {
180
+ const el = e.currentTarget;
181
+ if (el.scrollWidth <= el.clientWidth)
182
+ return;
183
+ const rect = el.getBoundingClientRect();
184
+ this._showTip(this.description ?? '', rect.left + rect.width / 2, rect.top);
185
+ };
186
+ this._onLabelEnter = (e) => {
187
+ const el = e.currentTarget;
188
+ if (el.scrollWidth <= el.clientWidth)
189
+ return;
190
+ const rect = el.getBoundingClientRect();
191
+ this._showTip(this.label ?? '', rect.left + rect.width / 2, rect.top);
164
192
  };
165
193
  this._onGaugeEnter = (e) => {
166
194
  const rect = e.currentTarget.getBoundingClientRect();
@@ -203,6 +231,7 @@ let NileKpiChart = class NileKpiChart extends NileElement {
203
231
  this.style.removeProperty(prop);
204
232
  };
205
233
  const len = (val) => this.formatCssLength(val) ?? '';
234
+ set('--nile-kpi-accent-color', this.accentColor);
206
235
  set('--nile-kpi-card-bg', this.cardBackground);
207
236
  set('--nile-kpi-card-border-color', this.cardBorderColor);
208
237
  set('--nile-kpi-card-border-width', len(this.cardBorderWidth));
@@ -252,11 +281,12 @@ let NileKpiChart = class NileKpiChart extends NileElement {
252
281
  }
253
282
  formatTooltipNumber(n) {
254
283
  const maxFractionDigits = Number.isInteger(n) ? 0 : 6;
255
- return new Intl.NumberFormat(undefined, {
284
+ const grouped = new Intl.NumberFormat(this.locale || undefined, {
256
285
  useGrouping: true,
257
286
  minimumFractionDigits: 0,
258
287
  maximumFractionDigits: maxFractionDigits,
259
288
  }).format(n);
289
+ return `${grouped}${this.unit ?? ''}`;
260
290
  }
261
291
  inferSparklineTooltipScale() {
262
292
  if (!this.sparkline?.length)
@@ -284,6 +314,85 @@ let NileKpiChart = class NileKpiChart extends NileElement {
284
314
  : this.formatTooltipNumber(numeric);
285
315
  return `${prefix}${valueText}${suffix}`.trim();
286
316
  }
317
+ formatValue(raw) {
318
+ const fmt = this.valueFormat;
319
+ const baseUnit = this.unit ?? '';
320
+ const abs = Math.abs(raw);
321
+ const sign = raw < 0 ? '-' : '';
322
+ const maxFrac = Number.isInteger(raw) ? 0 : 6;
323
+ const tooltipLocale = this.locale || undefined;
324
+ const displayLocale = this.locale || undefined;
325
+ const full = `${new Intl.NumberFormat(tooltipLocale, {
326
+ useGrouping: true, minimumFractionDigits: 0, maximumFractionDigits: maxFrac,
327
+ }).format(raw)}${baseUnit}`;
328
+ const display0 = `${new Intl.NumberFormat(displayLocale, {
329
+ useGrouping: true, minimumFractionDigits: 0, maximumFractionDigits: maxFrac,
330
+ }).format(raw)}${baseUnit}`;
331
+ if (fmt === 'none')
332
+ return { display: display0, full, abbreviated: false };
333
+ let divisor = 0;
334
+ let magnitude = '';
335
+ if (fmt === 'K') {
336
+ divisor = 1e3;
337
+ magnitude = 'K';
338
+ }
339
+ else if (fmt === 'M') {
340
+ divisor = 1e6;
341
+ magnitude = 'M';
342
+ }
343
+ else if (fmt === 'B') {
344
+ divisor = 1e9;
345
+ magnitude = 'B';
346
+ }
347
+ else if (fmt === 'T') {
348
+ divisor = 1e12;
349
+ magnitude = 'T';
350
+ }
351
+ else {
352
+ if (abs >= 1e12) {
353
+ divisor = 1e12;
354
+ magnitude = 'T';
355
+ }
356
+ else if (abs >= 1e9) {
357
+ divisor = 1e9;
358
+ magnitude = 'B';
359
+ }
360
+ else if (abs >= 1e6) {
361
+ divisor = 1e6;
362
+ magnitude = 'M';
363
+ }
364
+ else if (abs >= 1e3) {
365
+ divisor = 1e3;
366
+ magnitude = 'K';
367
+ }
368
+ }
369
+ if (!divisor)
370
+ return { display: display0, full, abbreviated: false };
371
+ const divided = abs / divisor;
372
+ let decimals;
373
+ if (this.precision !== null) {
374
+ decimals = Math.max(0, Math.floor(this.precision));
375
+ }
376
+ else {
377
+ decimals = divided >= 100 ? 0 : divided >= 10 ? 1 : 2;
378
+ }
379
+ let numStr;
380
+ if (this._hc) {
381
+ numStr = this._hc.numberFormat(divided, decimals, undefined, '');
382
+ if (this.precision === null) {
383
+ const dec = this._hc.options?.lang?.decimalPoint ?? '.';
384
+ const escapedDec = dec.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
385
+ numStr = numStr.replace(new RegExp(`${escapedDec}0*$`), '').replace(new RegExp(`${escapedDec}$`), '');
386
+ }
387
+ }
388
+ else {
389
+ numStr = divided.toFixed(decimals);
390
+ if (this.precision === null && numStr.includes('.')) {
391
+ numStr = numStr.replace(/\.?0+$/, '');
392
+ }
393
+ }
394
+ return { display: `${sign}${numStr}${magnitude}${baseUnit}`, full, abbreviated: true };
395
+ }
287
396
  // ── Config ───────────────────────────────────────────────────────────────
288
397
  applyConfig(cfg) {
289
398
  const { chart: c, aq } = cfg;
@@ -358,6 +467,8 @@ let NileKpiChart = class NileKpiChart extends NileElement {
358
467
  this.loadingText = c.loadingText;
359
468
  if (c.tooltipEnabled !== undefined)
360
469
  this.tooltipEnabled = c.tooltipEnabled;
470
+ if (c.accentColor !== undefined)
471
+ this.accentColor = c.accentColor;
361
472
  if (c.cardBackground !== undefined)
362
473
  this.cardBackground = c.cardBackground;
363
474
  if (c.cardBorderColor !== undefined)
@@ -400,6 +511,14 @@ let NileKpiChart = class NileKpiChart extends NileElement {
400
511
  this.loading = c.loading;
401
512
  if (c.options !== undefined)
402
513
  this.options = c.options;
514
+ if (c.valueFormat !== undefined)
515
+ this.valueFormat = c.valueFormat;
516
+ if (c.precision !== undefined)
517
+ this.precision = c.precision;
518
+ if (c.locale !== undefined)
519
+ this.locale = c.locale;
520
+ if (c.unit !== undefined)
521
+ this.unit = c.unit;
403
522
  if ('height' in c) {
404
523
  const h = this.formatCssLength(c.height);
405
524
  if (h) {
@@ -426,6 +545,9 @@ let NileKpiChart = class NileKpiChart extends NileElement {
426
545
  super.connectedCallback();
427
546
  ensureTooltipStyles();
428
547
  this._createTipEl();
548
+ if (!this._hc) {
549
+ getHighcharts().then(hc => { this._hc = hc; this.requestUpdate(); });
550
+ }
429
551
  if (this.config)
430
552
  this.applyConfig(this.config);
431
553
  }
@@ -460,7 +582,7 @@ let NileKpiChart = class NileKpiChart extends NileElement {
460
582
  this.initSparkline();
461
583
  }
462
584
  }
463
- const cssVarProps = ['cardBackground', 'cardBorderColor', 'cardBorderWidth', 'cardBorderRadius',
585
+ const cssVarProps = ['accentColor', 'cardBackground', 'cardBorderColor', 'cardBorderWidth', 'cardBorderRadius',
464
586
  'cardShadow', 'cardShadowHover', 'cardPaddingVertical', 'cardPaddingHorizontal', 'contentGap',
465
587
  'labelColor', 'labelFontSize', 'labelFontWeight', 'descriptionColor', 'descriptionFontSize',
466
588
  'prefixSuffixColor', 'prefixSuffixFontSize', 'trendUpColor', 'trendDownColor', 'trendNeutralColor',
@@ -589,7 +711,13 @@ let NileKpiChart = class NileKpiChart extends NileElement {
589
711
  borderWidth: 0,
590
712
  y: this.gaugeLabelYOffset,
591
713
  useHTML: true,
592
- format: `<div style="text-align:center"><span style="font-size:${labelFontSize};font-weight:${labelFontWeight};color:${labelColor}">${this.prefix}{y}${this.suffix}</span></div>`,
714
+ formatter: (() => {
715
+ const self = this;
716
+ return function () {
717
+ const fmtResult = self.formatValue(this.y ?? 0);
718
+ return `<div style="text-align:center"><span style="font-size:${labelFontSize};font-weight:${labelFontWeight};color:${labelColor}">${self.prefix}${fmtResult.display}${self.suffix}</span></div>`;
719
+ };
720
+ })(),
593
721
  },
594
722
  rounded: this.gaugeRounded,
595
723
  linecap: 'round',
@@ -675,9 +803,17 @@ let NileKpiChart = class NileKpiChart extends NileElement {
675
803
  return html `<div class="chart-loading">${this.loadingText}</div>`;
676
804
  }
677
805
  const isGauge = this.variant === 'gauge';
806
+ const rawNum = this.parseNumericValue(this.value);
807
+ const fmt = rawNum != null ? this.formatValue(rawNum) : null;
808
+ const displayValue = fmt ? fmt.display : String(this.value ?? '');
809
+ const showTooltip = !!fmt && fmt.display !== fmt.full;
678
810
  return html `
679
811
  <div class="kpi ${isGauge ? 'kpi--gauge' : ''}">
680
- ${this.label ? html `<p class="kpi-label">${this.label}</p>` : nothing}
812
+ ${this.label ? html `<p
813
+ class="kpi-label"
814
+ @mouseenter=${this._onLabelEnter}
815
+ @mouseleave=${this._onTipLeave}
816
+ >${this.label}</p>` : nothing}
681
817
 
682
818
  ${isGauge ? html `
683
819
  <div
@@ -691,10 +827,10 @@ let NileKpiChart = class NileKpiChart extends NileElement {
691
827
  ${!isGauge ? html `
692
828
  <h2
693
829
  class="kpi-value"
694
- @mouseenter=${this._onValueEnter}
695
- @mouseleave=${this._onTipLeave}
830
+ @mouseenter=${showTooltip ? this._onValueEnter : nothing}
831
+ @mouseleave=${showTooltip ? this._onTipLeave : nothing}
696
832
  >
697
- ${this.prefix ? html `<span class="kpi-prefix">${this.prefix}</span>` : nothing}${this.value}${this.suffix ? html `<span class="kpi-suffix">${this.suffix}</span>` : nothing}
833
+ ${this.prefix ? html `<span class="kpi-prefix">${this.prefix}</span>` : nothing}${displayValue}${this.suffix ? html `<span class="kpi-suffix">${this.suffix}</span>` : nothing}
698
834
  </h2>
699
835
  ` : nothing}
700
836
  ${!isGauge ? this.renderTrend() : nothing}
@@ -702,7 +838,11 @@ let NileKpiChart = class NileKpiChart extends NileElement {
702
838
 
703
839
  ${isGauge ? this.renderTrend() : nothing}
704
840
 
705
- ${this.description ? html `<p class="kpi-description">${this.description}</p>` : nothing}
841
+ ${this.description ? html `<p
842
+ class="kpi-description"
843
+ @mouseenter=${this._onDescEnter}
844
+ @mouseleave=${this._onTipLeave}
845
+ >${this.description}</p>` : nothing}
706
846
 
707
847
  ${this.sparkline.length && !isGauge ? html `<div class="kpi-sparkline"></div>` : nothing}
708
848
  </div>
@@ -851,6 +991,9 @@ __decorate([
851
991
  __decorate([
852
992
  property({ type: String, attribute: 'content-gap' })
853
993
  ], NileKpiChart.prototype, "contentGap", void 0);
994
+ __decorate([
995
+ property({ type: String, attribute: 'accent-color' })
996
+ ], NileKpiChart.prototype, "accentColor", void 0);
854
997
  __decorate([
855
998
  property({ type: String, attribute: 'label-color' })
856
999
  ], NileKpiChart.prototype, "labelColor", void 0);
@@ -887,6 +1030,18 @@ __decorate([
887
1030
  __decorate([
888
1031
  property({ type: Object })
889
1032
  ], NileKpiChart.prototype, "options", void 0);
1033
+ __decorate([
1034
+ property({ type: String, attribute: 'value-format' })
1035
+ ], NileKpiChart.prototype, "valueFormat", void 0);
1036
+ __decorate([
1037
+ property({ type: String })
1038
+ ], NileKpiChart.prototype, "unit", void 0);
1039
+ __decorate([
1040
+ property({ type: Number })
1041
+ ], NileKpiChart.prototype, "precision", void 0);
1042
+ __decorate([
1043
+ property({ type: String })
1044
+ ], NileKpiChart.prototype, "locale", void 0);
890
1045
  __decorate([
891
1046
  property({ type: Boolean, reflect: true, attribute: 'embed-in-nile-chart' })
892
1047
  ], NileKpiChart.prototype, "embedInNileChart", void 0);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aquera/nile-visualization",
3
- "version": "1.8.0",
3
+ "version": "2.0.0",
4
4
  "description": "A visualization Library for the Nile Design System",
5
5
  "license": "MIT",
6
6
  "author": "Aquera Inc",
@@ -64,7 +64,7 @@
64
64
  },
65
65
  "peerDependenciesMeta": {
66
66
  "@aquera/nile-data-grid": {
67
- "optional": true
67
+ "optional": true
68
68
  }
69
69
  },
70
70
  "devDependencies": {