@eshal-bot/chat-widget 0.2.24 → 0.2.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chat-widget-MarkdownRenderer-Co0fIss-.esm.js → chat-widget-MarkdownRenderer-DsgAO1cT.esm.js} +2 -2
- package/dist/{chat-widget-index-BMEiiPTA.esm.js → chat-widget-index-DjOa8SJO.esm.js} +1 -1
- package/dist/chat-widget-markdown-chunk.js +191 -19
- package/dist/chat-widget-markdown-chunk.min.js +1 -1
- package/dist/chat-widget.esm.js +1 -1
- package/dist/chat-widget.js +1 -1
- package/dist/chat-widget.min.js +1 -1
- package/dist/chat-widget.umd.js +7 -7
- package/package.json +1 -1
|
@@ -87838,11 +87838,81 @@
|
|
|
87838
87838
|
return null;
|
|
87839
87839
|
}
|
|
87840
87840
|
|
|
87841
|
+
// ── Figures side by side ───────────────────────────────────────────────────
|
|
87842
|
+
// A chart that compares figures (pre vs post GRP, the 1+/3+/5+ reach curves)
|
|
87843
|
+
// arrives with `props.series`, [{ key, dataKey, name }] built by A2uiBlock's
|
|
87844
|
+
// chartSeries() from the spec's `ys` and `names`: one bar or one line per
|
|
87845
|
+
// figure, named in a legend, its colour fixed by its place in the order. The
|
|
87846
|
+
// colours: the brand blue (docs/design-system), then amber, pink and cyan from
|
|
87847
|
+
// the frontend chart palette's families, an order checked for colour-blind
|
|
87848
|
+
// separation and 3:1 contrast on the widget's light and dark surfaces (on dark,
|
|
87849
|
+
// blue-500 stands in for the brand blue-700, which falls under 3:1 there).
|
|
87850
|
+
// Mirrors SERIES_PALETTE in the frontend's chartShared.tsx.
|
|
87851
|
+
const SERIES_COLORS = ['#1d4ed8', '#d97706', '#db2777', '#0891b2'];
|
|
87852
|
+
const SERIES_COLORS_DARK = ['#3b82f6', '#d97706', '#db2777', '#0891b2'];
|
|
87853
|
+
function seriesColor(i, isDark = false) {
|
|
87854
|
+
const colors = isDark ? SERIES_COLORS_DARK : SERIES_COLORS;
|
|
87855
|
+
return colors[i % colors.length];
|
|
87856
|
+
}
|
|
87857
|
+
|
|
87858
|
+
// The figures drawn side by side, or [] for a one-figure chart.
|
|
87859
|
+
function sideBySide(props) {
|
|
87860
|
+
return Array.isArray(props.series) && props.series.length > 1 ? props.series : [];
|
|
87861
|
+
}
|
|
87862
|
+
|
|
87863
|
+
// Each figure's money formatting (moneyFormatters by its own key, so spend
|
|
87864
|
+
// reads as money beside GRP), and the one axis's: money only when every
|
|
87865
|
+
// figure on it is.
|
|
87866
|
+
function seriesMoney(series, currency) {
|
|
87867
|
+
const each = series.map(s => moneyFormatters(currency, s.key));
|
|
87868
|
+
return {
|
|
87869
|
+
each,
|
|
87870
|
+
axis: each.length > 0 && each.every(Boolean) ? each[0] : null
|
|
87871
|
+
};
|
|
87872
|
+
}
|
|
87873
|
+
|
|
87874
|
+
// The tooltip value of a figure side by side, formatted as that figure. Its
|
|
87875
|
+
// line names the figure, so it is written in ink (seriesTooltipItem): amber
|
|
87876
|
+
// text on white falls under 4.5:1.
|
|
87877
|
+
function seriesTooltip(series, each, unit) {
|
|
87878
|
+
return (v, name, item) => {
|
|
87879
|
+
const money = each[series.findIndex(s => s.dataKey === (item && item.dataKey))];
|
|
87880
|
+
if (money) return money.full(v);
|
|
87881
|
+
return unit ? `${Number(v).toLocaleString()} ${unit}` : Number(v).toLocaleString();
|
|
87882
|
+
};
|
|
87883
|
+
}
|
|
87884
|
+
function seriesTooltipItem(series, inkColor) {
|
|
87885
|
+
return series.length > 0 ? {
|
|
87886
|
+
color: inkColor
|
|
87887
|
+
} : undefined;
|
|
87888
|
+
}
|
|
87889
|
+
|
|
87890
|
+
// The legend of figures side by side: above the plot, clear of slanted
|
|
87891
|
+
// category labels; its words in ink, the swatch carrying the colour.
|
|
87892
|
+
function seriesLegend(inkColor) {
|
|
87893
|
+
return /*#__PURE__*/jsxRuntimeExports.jsx(Legend, {
|
|
87894
|
+
verticalAlign: "top",
|
|
87895
|
+
iconSize: 10,
|
|
87896
|
+
wrapperStyle: {
|
|
87897
|
+
fontSize: 11,
|
|
87898
|
+
paddingBottom: 6
|
|
87899
|
+
},
|
|
87900
|
+
formatter: value => /*#__PURE__*/jsxRuntimeExports.jsx("span", {
|
|
87901
|
+
style: {
|
|
87902
|
+
color: inkColor
|
|
87903
|
+
},
|
|
87904
|
+
children: value
|
|
87905
|
+
})
|
|
87906
|
+
});
|
|
87907
|
+
}
|
|
87908
|
+
|
|
87841
87909
|
/**
|
|
87842
87910
|
* Recharts bar chart - mirrors agent-sdk's eshalRenderers.BarChart.
|
|
87843
87911
|
*
|
|
87844
87912
|
* Expects `props.data` to be an array of `{ label, value }` objects
|
|
87845
|
-
* (already normalized by A2uiBlock's numericData helper)
|
|
87913
|
+
* (already normalized by A2uiBlock's numericData helper), or, for figures
|
|
87914
|
+
* side by side, `{ label, s0, s1, ... }` points with `props.series`: grouped
|
|
87915
|
+
* bars, one per figure, named in a legend.
|
|
87846
87916
|
*/
|
|
87847
87917
|
function BarChartRenderer({
|
|
87848
87918
|
props,
|
|
@@ -87855,6 +87925,9 @@
|
|
|
87855
87925
|
// Human series name for the tooltip ("Average Salary"), so it no longer
|
|
87856
87926
|
// reads the generic dataKey "value".
|
|
87857
87927
|
const seriesName = props.valueLabel || undefined;
|
|
87928
|
+
const series = sideBySide(props);
|
|
87929
|
+
const figures = seriesMoney(series, props.currency);
|
|
87930
|
+
const axisMoney = series.length > 0 ? figures.axis : money;
|
|
87858
87931
|
const borderColor = isDark ? '#374151' : '#e2e8f0';
|
|
87859
87932
|
const bgColor = isDark ? '#1f2937' : '#ffffff';
|
|
87860
87933
|
const labelColor = isDark ? '#9ca3af' : '#64748b';
|
|
@@ -87938,11 +88011,12 @@
|
|
|
87938
88011
|
},
|
|
87939
88012
|
angle: xAngle,
|
|
87940
88013
|
textAnchor: xAnchor,
|
|
87941
|
-
interval: 0
|
|
87942
|
-
|
|
87943
|
-
|
|
87944
|
-
|
|
87945
|
-
|
|
88014
|
+
interval: 0
|
|
88015
|
+
// Each label arrives formatted by A2uiBlock (formatAxisTick), so the
|
|
88016
|
+
// axis shows it as given, as the line and pie charts do. Capitalising
|
|
88017
|
+
// it again would split "CNBC-TV18" and turn "McDonald's" into
|
|
88018
|
+
// "McDonald'S".
|
|
88019
|
+
,
|
|
87946
88020
|
label: props.xAxisLabel ? {
|
|
87947
88021
|
value: props.xAxisLabel,
|
|
87948
88022
|
position: 'insideBottom',
|
|
@@ -87963,9 +88037,10 @@
|
|
|
87963
88037
|
fontSize: 11,
|
|
87964
88038
|
fill: labelColor
|
|
87965
88039
|
} : undefined,
|
|
87966
|
-
tickFormatter: v =>
|
|
88040
|
+
tickFormatter: v => axisMoney ? axisMoney.compact(v) : props.unit ? `${formatCompactNumber(v)} ${props.unit}` : formatCompactNumber(v)
|
|
87967
88041
|
}), /*#__PURE__*/jsxRuntimeExports.jsx(Tooltip, {
|
|
87968
|
-
formatter: v => money ? money.full(v) : props.unit ? `${Number(v).toLocaleString()} ${props.unit}` : Number(v).toLocaleString(),
|
|
88042
|
+
formatter: series.length > 0 ? seriesTooltip(series, figures.each, props.unit) : v => money ? money.full(v) : props.unit ? `${Number(v).toLocaleString()} ${props.unit}` : Number(v).toLocaleString(),
|
|
88043
|
+
itemStyle: seriesTooltipItem(series, titleColor),
|
|
87969
88044
|
contentStyle: {
|
|
87970
88045
|
background: tooltipBg,
|
|
87971
88046
|
border: `1px solid ${borderColor}`,
|
|
@@ -87973,7 +88048,12 @@
|
|
|
87973
88048
|
fontSize: 12,
|
|
87974
88049
|
color: titleColor
|
|
87975
88050
|
}
|
|
87976
|
-
}), /*#__PURE__*/jsxRuntimeExports.jsx(Bar, {
|
|
88051
|
+
}), series.length > 0 && seriesLegend(labelColor), series.length > 0 ? series.map((s, i) => /*#__PURE__*/jsxRuntimeExports.jsx(Bar, {
|
|
88052
|
+
dataKey: s.dataKey,
|
|
88053
|
+
name: s.name,
|
|
88054
|
+
fill: seriesColor(i, isDark),
|
|
88055
|
+
radius: [2, 2, 0, 0]
|
|
88056
|
+
}, s.dataKey)) : /*#__PURE__*/jsxRuntimeExports.jsx(Bar, {
|
|
87977
88057
|
dataKey: "value",
|
|
87978
88058
|
name: seriesName,
|
|
87979
88059
|
fill: "#3b82f6",
|
|
@@ -88242,7 +88322,9 @@
|
|
|
88242
88322
|
|
|
88243
88323
|
/**
|
|
88244
88324
|
* Recharts line / area chart - replaces hand-rolled LineSvg.
|
|
88245
|
-
* `props.data` must be an array of `{ label, value }` objects
|
|
88325
|
+
* `props.data` must be an array of `{ label, value }` objects, or, for
|
|
88326
|
+
* figures side by side, `{ label, s0, s1, ... }` points with `props.series`:
|
|
88327
|
+
* one line each, named in a legend.
|
|
88246
88328
|
* Set `area={true}` to fill under the line.
|
|
88247
88329
|
*/
|
|
88248
88330
|
function LineChartRenderer({
|
|
@@ -88253,6 +88335,12 @@
|
|
|
88253
88335
|
const data = Array.isArray(props.data) ? props.data : [];
|
|
88254
88336
|
const money = moneyFormatters(props.currency, props.yKey);
|
|
88255
88337
|
const seriesName = props.valueLabel || undefined;
|
|
88338
|
+
const series = sideBySide(props);
|
|
88339
|
+
const figures = seriesMoney(series, props.currency);
|
|
88340
|
+
const axisMoney = series.length > 0 ? figures.axis : money;
|
|
88341
|
+
// Several lines over a long run of periods (26 weeks of reach): every few
|
|
88342
|
+
// ticks and no dots, so the lines stay legible at the widget's width.
|
|
88343
|
+
const crowded = series.length > 0 && data.length > 12;
|
|
88256
88344
|
const borderColor = isDark ? '#374151' : '#e2e8f0';
|
|
88257
88345
|
const bgColor = isDark ? '#1f2937' : '#ffffff';
|
|
88258
88346
|
const labelColor = isDark ? '#9ca3af' : '#64748b';
|
|
@@ -88332,7 +88420,7 @@
|
|
|
88332
88420
|
},
|
|
88333
88421
|
angle: 0,
|
|
88334
88422
|
textAnchor: "middle",
|
|
88335
|
-
interval: 0,
|
|
88423
|
+
interval: crowded ? 'preserveStartEnd' : 0,
|
|
88336
88424
|
label: props.xAxisLabel ? {
|
|
88337
88425
|
value: props.xAxisLabel,
|
|
88338
88426
|
position: 'insideBottom',
|
|
@@ -88346,9 +88434,10 @@
|
|
|
88346
88434
|
fontSize: 11,
|
|
88347
88435
|
fill: labelColor
|
|
88348
88436
|
},
|
|
88349
|
-
tickFormatter: v =>
|
|
88437
|
+
tickFormatter: v => axisMoney ? axisMoney.compact(v) : props.unit ? `${formatCompactNumber(v)} ${props.unit}` : formatCompactNumber(v)
|
|
88350
88438
|
}), /*#__PURE__*/jsxRuntimeExports.jsx(Tooltip, {
|
|
88351
|
-
formatter: v => money ? money.full(v) : props.unit ? `${Number(v).toLocaleString()} ${props.unit}` : Number(v).toLocaleString(),
|
|
88439
|
+
formatter: series.length > 0 ? seriesTooltip(series, figures.each, props.unit) : v => money ? money.full(v) : props.unit ? `${Number(v).toLocaleString()} ${props.unit}` : Number(v).toLocaleString(),
|
|
88440
|
+
itemStyle: seriesTooltipItem(series, titleColor),
|
|
88352
88441
|
contentStyle: {
|
|
88353
88442
|
background: tooltipBg,
|
|
88354
88443
|
border: `1px solid ${borderColor}`,
|
|
@@ -88356,7 +88445,33 @@
|
|
|
88356
88445
|
fontSize: 12,
|
|
88357
88446
|
color: titleColor
|
|
88358
88447
|
}
|
|
88359
|
-
}),
|
|
88448
|
+
}), series.length > 0 && seriesLegend(labelColor), series.length > 0 ? series.map((s, i) => {
|
|
88449
|
+
const color = seriesColor(i, isDark);
|
|
88450
|
+
const dot = crowded ? false : {
|
|
88451
|
+
r: 3,
|
|
88452
|
+
fill: color
|
|
88453
|
+
};
|
|
88454
|
+
return area ? /*#__PURE__*/jsxRuntimeExports.jsx(Area, {
|
|
88455
|
+
type: "monotone",
|
|
88456
|
+
dataKey: s.dataKey,
|
|
88457
|
+
name: s.name,
|
|
88458
|
+
stroke: color,
|
|
88459
|
+
fill: color,
|
|
88460
|
+
fillOpacity: 0.15,
|
|
88461
|
+
strokeWidth: 2,
|
|
88462
|
+
dot: dot
|
|
88463
|
+
}, s.dataKey) : /*#__PURE__*/jsxRuntimeExports.jsx(Line, {
|
|
88464
|
+
type: "monotone",
|
|
88465
|
+
dataKey: s.dataKey,
|
|
88466
|
+
name: s.name,
|
|
88467
|
+
stroke: color,
|
|
88468
|
+
strokeWidth: 2,
|
|
88469
|
+
dot: dot,
|
|
88470
|
+
activeDot: {
|
|
88471
|
+
r: 5
|
|
88472
|
+
}
|
|
88473
|
+
}, s.dataKey);
|
|
88474
|
+
}) : area ? /*#__PURE__*/jsxRuntimeExports.jsx(Area, {
|
|
88360
88475
|
type: "monotone",
|
|
88361
88476
|
dataKey: "value",
|
|
88362
88477
|
name: seriesName,
|
|
@@ -88738,6 +88853,40 @@
|
|
|
88738
88853
|
}).filter(d => Number.isFinite(d.value));
|
|
88739
88854
|
}
|
|
88740
88855
|
|
|
88856
|
+
// The figures a chart compares side by side: the spec's `ys` (the runtime's
|
|
88857
|
+
// agents/data_charts.py writes them for pre vs post GRP, the 1+/3+/5+ reach
|
|
88858
|
+
// curves), each named by `names` or else its prettified key. Two or more that
|
|
88859
|
+
// the rows carry, else none, and a one-figure spec renders as before. Each
|
|
88860
|
+
// figure is read under its own data key (s0, s1, ...), so a figure whose name
|
|
88861
|
+
// matches the category's key ("label") cannot overwrite it.
|
|
88862
|
+
function chartSeries(spec) {
|
|
88863
|
+
const ys = Array.isArray(spec.ys) ? spec.ys.filter(k => typeof k === 'string' && k) : [];
|
|
88864
|
+
const sample = Array.isArray(spec.data) ? spec.data.find(row => row && typeof row === 'object') : null;
|
|
88865
|
+
const keys = sample ? [...new Set(ys)].filter(k => Object.prototype.hasOwnProperty.call(sample, k)) : [];
|
|
88866
|
+
if (keys.length < 2) return [];
|
|
88867
|
+
const names = spec.names && typeof spec.names === 'object' ? spec.names : {};
|
|
88868
|
+
return keys.map((key, i) => ({
|
|
88869
|
+
key,
|
|
88870
|
+
dataKey: `s${i}`,
|
|
88871
|
+
name: typeof names[key] === 'string' && names[key].trim() ? names[key].trim() : prettifyLabel(key)
|
|
88872
|
+
}));
|
|
88873
|
+
}
|
|
88874
|
+
|
|
88875
|
+
// numericData() for figures side by side: the label and each figure under its
|
|
88876
|
+
// series' data key, null where a row has none; a row with none of them goes.
|
|
88877
|
+
function seriesData(data, xKey, series) {
|
|
88878
|
+
return (data || []).filter(row => row && typeof row === 'object').map(row => {
|
|
88879
|
+
const point = {
|
|
88880
|
+
label: formatAxisTick(row[xKey], xKey)
|
|
88881
|
+
};
|
|
88882
|
+
for (const s of series) {
|
|
88883
|
+
const value = row[s.key] == null ? NaN : Number(row[s.key]);
|
|
88884
|
+
point[s.dataKey] = Number.isFinite(value) ? value : null;
|
|
88885
|
+
}
|
|
88886
|
+
return point;
|
|
88887
|
+
}).filter(point => series.some(s => point[s.dataKey] !== null));
|
|
88888
|
+
}
|
|
88889
|
+
|
|
88741
88890
|
// ── Chart (SVG: line / bar / pie / donut + everything-else fallback) ─────
|
|
88742
88891
|
|
|
88743
88892
|
function Chart({
|
|
@@ -88745,12 +88894,16 @@
|
|
|
88745
88894
|
type,
|
|
88746
88895
|
isDark
|
|
88747
88896
|
}) {
|
|
88897
|
+
const series = chartSeries(spec);
|
|
88748
88898
|
const {
|
|
88749
88899
|
x,
|
|
88750
88900
|
y
|
|
88751
|
-
} = inferKeys(spec.data, spec.x, spec.y);
|
|
88752
|
-
const rows = numericData(spec.data, x, y);
|
|
88901
|
+
} = inferKeys(spec.data, spec.x, series.length > 0 ? series[0].key : spec.y);
|
|
88753
88902
|
const t = String(type || '').trim().toLowerCase();
|
|
88903
|
+
// Figures side by side draw as grouped bars or one line each; a pie holds
|
|
88904
|
+
// one figure, so a spec of several typed pie draws its first.
|
|
88905
|
+
const sideBySide = series.length > 0 && t !== 'pie' && t !== 'donut';
|
|
88906
|
+
const rows = sideBySide ? seriesData(spec.data, x, series) : numericData(spec.data, x, y);
|
|
88754
88907
|
const chartProps = {
|
|
88755
88908
|
title: spec.title,
|
|
88756
88909
|
data: rows,
|
|
@@ -88765,7 +88918,9 @@
|
|
|
88765
88918
|
valueLabel: prettifyLabel(y),
|
|
88766
88919
|
// The currency the chart states ("USD", "INR", "₹"): the only source of
|
|
88767
88920
|
// a currency symbol (widgetCatalog moneyFormatters).
|
|
88768
|
-
currency: spec.currency
|
|
88921
|
+
currency: spec.currency,
|
|
88922
|
+
// Figures side by side (chartSeries): one bar or line each, in a legend.
|
|
88923
|
+
series: sideBySide ? series : undefined
|
|
88769
88924
|
};
|
|
88770
88925
|
if (t === 'pie') return /*#__PURE__*/jsxRuntimeExports.jsx(PieChartRenderer, {
|
|
88771
88926
|
props: chartProps,
|
|
@@ -90383,11 +90538,28 @@
|
|
|
90383
90538
|
const MONTH_NAMES = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
|
90384
90539
|
const CURRENCY_KEY_RE = /(^|[_\W])(price|salary|cost|amount|revenue|expense|total|value|budget|spend|income|sale|balance)/i;
|
|
90385
90540
|
const MONTH_KEY_RE = /(^|[_\W])month/i;
|
|
90541
|
+
|
|
90542
|
+
// Only a column-style value is reworded: one with an underscore
|
|
90543
|
+
// (office_supplies), one without capitals (kebab-case, all-lower words)
|
|
90544
|
+
// or a camelCase key. A value written with capitals is a name and stays as
|
|
90545
|
+
// written ("DD Sports", "Republic TV", "GEC"), as does a word written with
|
|
90546
|
+
// capitals inside a key (GRP_pre -> "GRP Pre"). Lower-casing every word but
|
|
90547
|
+
// its first letter read those channels as "Dd Sports", "Republic Tv" and
|
|
90548
|
+
// "Gec" (Media Prowess, Oct 2026).
|
|
90386
90549
|
function prettifyLabel(value) {
|
|
90387
90550
|
if (value === null || value === undefined) return '';
|
|
90388
|
-
const s = String(value);
|
|
90551
|
+
const s = String(value).replace(/\s+/g, ' ').trim();
|
|
90389
90552
|
if (!s) return '';
|
|
90390
|
-
|
|
90553
|
+
if (!isColumnStyle(s)) return s;
|
|
90554
|
+
return s.replace(/[_\-]+/g, ' ').replace(/([a-z])([A-Z])/g, '$1 $2').replace(/\s+/g, ' ').trim().split(' ').map(w => w === w.toLowerCase() ? w.charAt(0).toUpperCase() + w.slice(1) : w).join(' ');
|
|
90555
|
+
}
|
|
90556
|
+
|
|
90557
|
+
// A camelCase key ("camelCaseKey", "totalSpend"): two lower-case letters
|
|
90558
|
+
// before the first capital, so names such as "iPhone", "eBay" and "kWh"
|
|
90559
|
+
// stay as written.
|
|
90560
|
+
const CAMEL_CASE_KEY_RE = /^[a-z]{2}[a-z0-9]*[A-Z][A-Za-z0-9]*$/;
|
|
90561
|
+
function isColumnStyle(s) {
|
|
90562
|
+
return s.includes('_') || s === s.toLowerCase() || CAMEL_CASE_KEY_RE.test(s);
|
|
90391
90563
|
}
|
|
90392
90564
|
function isCurrencyKey(key) {
|
|
90393
90565
|
return typeof key === 'string' && CURRENCY_KEY_RE.test(key);
|