@svgrid/grid 3.0.1 → 3.0.2

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 (77) hide show
  1. package/dist/GridFooter.svelte +14 -5
  2. package/dist/GridFooter.svelte.d.ts +8 -0
  3. package/dist/GridMenus.svelte +18 -10
  4. package/dist/GridMenus.svelte.d.ts +2 -1
  5. package/dist/SvGrid.controller.svelte.d.ts +17 -0
  6. package/dist/SvGrid.controller.svelte.js +128 -14
  7. package/dist/SvGrid.css +79 -10
  8. package/dist/SvGrid.svelte +191 -186
  9. package/dist/SvGrid.types.d.ts +42 -1
  10. package/dist/SvGridChart.svelte +571 -41
  11. package/dist/SvGridChart.svelte.d.ts +63 -1
  12. package/dist/SvGridChartPanel.svelte +169 -21
  13. package/dist/SvGridChartView.svelte +9 -0
  14. package/dist/SvGridChartView.svelte.d.ts +7 -0
  15. package/dist/SvGroupCell.svelte +28 -3
  16. package/dist/SvGroupCell.svelte.d.ts +8 -0
  17. package/dist/SvRowGroupPanel.svelte +20 -4
  18. package/dist/SvRowGroupPanel.svelte.d.ts +8 -0
  19. package/dist/ai.d.ts +11 -2
  20. package/dist/ai.js +51 -7
  21. package/dist/cdn/GridMenus-DyFA-QxA.js +602 -0
  22. package/dist/cdn/{GridMenus-DFB6iwF8.js → GridMenus-M2XP9t0_.js} +152 -150
  23. package/dist/cdn/SvGridChart-DAb9RbRs.js +1480 -0
  24. package/dist/cdn/SvGridChart-Yl-IXZFO.js +1481 -0
  25. package/dist/cdn/SvGridChartPanel-DayQpDsR.js +834 -0
  26. package/dist/cdn/SvGridChartPanel-aqf8n-vJ.js +810 -0
  27. package/dist/cdn/{SvGridChartView-BhUEJ5ki.js → SvGridChartView-CxfakxR0.js} +5 -3
  28. package/dist/cdn/{SvGridChartView-00LPUHL1.js → SvGridChartView-Dm_YEx9L.js} +5 -3
  29. package/dist/cdn/cell-formatting-C2Hf5gqd.js +86 -0
  30. package/dist/cdn/chart-CKJRCPOk.js +1652 -0
  31. package/dist/cdn/{export-format-Cv1Dll6k.js → export-format-CUDLy2yn.js} +84 -168
  32. package/dist/cdn/{src-C8QjSaq-.js → src-BJ2opd0j.js} +3608 -3414
  33. package/dist/cdn/{src-D0hO2eYN.js → src-DNbz94Ct.js} +8617 -8423
  34. package/dist/cdn/svgrid.js +16 -15
  35. package/dist/cdn/svgrid.svelte-external.js +16 -15
  36. package/dist/cell-formatting.d.ts +7 -0
  37. package/dist/cell-formatting.js +7 -1
  38. package/dist/chart-export.d.ts +23 -2
  39. package/dist/chart-export.js +80 -6
  40. package/dist/chart.d.ts +410 -18
  41. package/dist/chart.js +824 -24
  42. package/dist/grid-icons.d.ts +49 -0
  43. package/dist/grid-icons.js +86 -0
  44. package/dist/index.d.ts +3 -2
  45. package/dist/index.js +3 -2
  46. package/package.json +11 -11
  47. package/src/GridFooter.svelte +14 -5
  48. package/src/GridMenus.svelte +18 -10
  49. package/src/SvGrid.controller.svelte.ts +146 -13
  50. package/src/SvGrid.css +79 -10
  51. package/src/SvGrid.svelte +191 -186
  52. package/src/SvGrid.types.ts +42 -1
  53. package/src/SvGridChart.svelte +571 -41
  54. package/src/SvGridChart.test.ts +243 -1
  55. package/src/SvGridChartPanel.svelte +169 -21
  56. package/src/SvGridChartView.svelte +9 -0
  57. package/src/SvGroupCell.svelte +28 -3
  58. package/src/SvRowGroupPanel.svelte +20 -4
  59. package/src/ai.test.ts +60 -1
  60. package/src/ai.ts +59 -6
  61. package/src/cell-formatting.ts +7 -1
  62. package/src/chart-export.test.ts +112 -0
  63. package/src/chart-export.ts +76 -8
  64. package/src/chart.test.ts +830 -1
  65. package/src/chart.ts +1053 -32
  66. package/src/grid-icons.test.ts +46 -0
  67. package/src/grid-icons.ts +184 -0
  68. package/src/icon-overrides.grid.test.ts +188 -0
  69. package/src/icon-seam.test.ts +100 -0
  70. package/src/index.ts +19 -0
  71. package/src/svgrid.charting.test.ts +120 -0
  72. package/dist/cdn/GridMenus-CYzOvmNQ.js +0 -600
  73. package/dist/cdn/SvGridChart-BEJmNNx9.js +0 -1203
  74. package/dist/cdn/SvGridChart-BwVos976.js +0 -1202
  75. package/dist/cdn/SvGridChartPanel-BOknOkrP.js +0 -561
  76. package/dist/cdn/SvGridChartPanel-D2PjII4O.js +0 -585
  77. package/dist/cdn/chart-i4XcXyHJ.js +0 -1214
package/dist/ai.js CHANGED
@@ -511,7 +511,7 @@ export async function aiChart(api, query, opts = {}) {
511
511
  `into a strict-JSON chart plan the grid can render.\n\n` +
512
512
  `Columns:\n${schemaToPromptBlock(schema)}\n\n` +
513
513
  `Output JSON schema:\n` +
514
- `{ "type": "bar"|"line"|"area"|"pie", ` +
514
+ `{ "type": "bar"|"line"|"area"|"pie"|"treemap"|"funnel"|"waterfall"|"radar"|"heatmap"|"boxplot"|"gauge"|"calendar"|"sankey", ` +
515
515
  `"dimension": "<a categorical column to group by>", ` +
516
516
  `"series": "<a second categorical column to split into series, or null>", ` +
517
517
  `"measure": "<a numeric column to aggregate>", ` +
@@ -523,6 +523,16 @@ export async function aiChart(api, query, opts = {}) {
523
523
  `"rationale": "<one-sentence explanation>" }\n\n` +
524
524
  `Rules: pick "dimension" and "series" from text/date columns and "measure" ` +
525
525
  `from a numeric column; use only column names from the list above; ` +
526
+ `default to "bar" unless the request clearly wants another type. ` +
527
+ `Type hints: share/proportion/breakdown -> pie; nested/hierarchy/"what makes ` +
528
+ `up" -> treemap; drop-off/conversion/stages/pipeline -> funnel; ` +
529
+ `running total/contribution/bridge -> waterfall; comparing several measures ` +
530
+ `per item -> radar; a grid of two dimensions -> heatmap (needs "series"); ` +
531
+ `spread/distribution/variance/outliers/percentiles -> boxplot; a single ` +
532
+ `number vs a target -> gauge (leave "dimension" null); a year of daily ` +
533
+ `activity -> calendar (dimension must be a date column); flow between two ` +
534
+ `things -> sankey (needs "series": dimension is the source, series the ` +
535
+ `target). ` +
526
536
  `"stacked"/"stack" -> stacked:true; "log"/"logarithmic" -> logScale:true; ` +
527
537
  `"over time"/"by date"/a date dimension -> timeAxis:true; ` +
528
538
  `money/revenue/price/$ -> valueFormat:"currency"; rate/%/share -> valueFormat:"percent"; ` +
@@ -537,7 +547,11 @@ export async function aiChart(api, query, opts = {}) {
537
547
  });
538
548
  const valid = new Set(schema.map((c) => c.field));
539
549
  const numericFields = new Set(schema.filter((c) => c.type === 'number').map((c) => c.field));
540
- const CHART_TYPES = ['bar', 'line', 'area', 'pie'];
550
+ const CHART_TYPES = [
551
+ 'bar', 'line', 'area', 'pie',
552
+ 'treemap', 'funnel', 'waterfall', 'radar',
553
+ 'heatmap', 'boxplot', 'gauge', 'calendar', 'sankey',
554
+ ];
541
555
  plan.type = CHART_TYPES.includes(plan.type) ? plan.type : 'bar';
542
556
  plan.dimension = plan.dimension && valid.has(plan.dimension) ? plan.dimension : null;
543
557
  plan.series = plan.series && valid.has(plan.series) && plan.series !== plan.dimension ? plan.series : null;
@@ -545,6 +559,21 @@ export async function aiChart(api, query, opts = {}) {
545
559
  plan.measure && numericFields.has(plan.measure)
546
560
  ? plan.measure
547
561
  : (schema.find((c) => c.type === 'number')?.field ?? null);
562
+ // Shape check. Some types need more than a dimension and a measure, and a
563
+ // plan that does not satisfy one renders an empty frame - the model asked for
564
+ // a chart the data cannot make. Fall back to a bar, which any dimension and
565
+ // measure can draw, rather than showing nothing and blaming the request.
566
+ const dateFields = new Set(schema.filter((c) => c.type === 'date').map((c) => c.field));
567
+ const needsSplit = plan.type === 'heatmap' || plan.type === 'sankey';
568
+ if (needsSplit && !plan.series)
569
+ plan.type = 'bar';
570
+ if (plan.type === 'calendar' && !(plan.dimension && dateFields.has(plan.dimension)))
571
+ plan.type = 'bar';
572
+ // A gauge is one number: it has no category axis, so a dimension is noise.
573
+ if (plan.type === 'gauge')
574
+ plan.dimension = null;
575
+ if (plan.type !== 'gauge' && !plan.dimension)
576
+ plan.type = 'bar';
548
577
  plan.reduce = ['sum', 'avg', 'count'].includes(plan.reduce) ? plan.reduce : 'sum';
549
578
  plan.stacked = plan.stacked === true;
550
579
  plan.logScale = plan.logScale === true;
@@ -640,10 +669,22 @@ function buildMockChart(prompt) {
640
669
  const typed = extractFieldTypes(prompt);
641
670
  const textFields = typed.filter((f) => f.type === 'string' || f.type === 'date').map((f) => f.name);
642
671
  const numberFields = typed.filter((f) => f.type === 'number').map((f) => f.name);
643
- const type = /\bline\b|\btrend\b|over time/.test(q) ? 'line'
644
- : /\barea\b/.test(q) ? 'area'
645
- : /\bpie\b|share|proportion|breakdown/.test(q) ? 'pie'
646
- : 'bar';
672
+ // Mirrors the type hints in the real prompt, so the bundled offline provider
673
+ // can reach the same charts a model can. Ordered most-specific first: "share
674
+ // of the pipeline" is a funnel request, not a pie one.
675
+ const type = /\bfunnel\b|drop.?off|conversion|\bstages?\b|pipeline/.test(q) ? 'funnel'
676
+ : /\bwaterfall\b|running total|contribution|\bbridge\b/.test(q) ? 'waterfall'
677
+ : /\btree ?map\b|nested|hierarch/.test(q) ? 'treemap'
678
+ : /\bradar\b|spider|multi.?measure/.test(q) ? 'radar'
679
+ : /\bheat ?map\b/.test(q) ? 'heatmap'
680
+ : /\bbox ?plot\b|spread|distribution|variance|outlier|percentile|quartile/.test(q) ? 'boxplot'
681
+ : /\bgauge\b|\bdial\b|vs target|against target/.test(q) ? 'gauge'
682
+ : /\bcalendar\b|daily activity|year of/.test(q) ? 'calendar'
683
+ : /\bsankey\b|\bflow\b/.test(q) ? 'sankey'
684
+ : /\bline\b|\btrend\b|over time/.test(q) ? 'line'
685
+ : /\barea\b/.test(q) ? 'area'
686
+ : /\bpie\b|share|proportion|breakdown/.test(q) ? 'pie'
687
+ : 'bar';
647
688
  const byMatch = q.match(/\bby\s+([a-z0-9_ ]+?)(?:\s+(?:split|stacked|grouped|by|as|,|$))/);
648
689
  const pickText = (hint) => {
649
690
  if (hint) {
@@ -654,7 +695,10 @@ function buildMockChart(prompt) {
654
695
  return null;
655
696
  };
656
697
  const dimension = pickText(byMatch?.[1]) ?? textFields[0] ?? null;
657
- const series = /\b(split|stack(?:ed)?|by product|by category|per)\b/.test(q)
698
+ // Heatmap and sankey are two-dimension charts: without a split the shape
699
+ // check downgrades them to a bar, so the mock would answer "heatmap" with a
700
+ // bar chart and look broken rather than offline.
701
+ const series = /\b(split|stack(?:ed)?|by product|by category|per)\b/.test(q) || type === 'heatmap' || type === 'sankey'
658
702
  ? (textFields.find((t) => t !== dimension) ?? null)
659
703
  : null;
660
704
  const measure = numberFields.find((n) => q.includes(n.toLowerCase())) ?? numberFields[0] ?? null;