@fusedashlabs/widgets 0.4.0 → 0.4.1

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 (110) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +1 -1
  3. package/dist/components/chart-renderer/element/ui9000-chart-renderer.d.ts +1 -0
  4. package/dist/components/chart-renderer/element/ui9000-chart-renderer.d.ts.map +1 -1
  5. package/dist/components/chart-renderer/element/ui9000-chart-renderer.js +11 -1
  6. package/dist/components/chart-renderer/element/ui9000-chart-renderer.js.map +1 -1
  7. package/dist/components/chart-renderer/lib/registry.d.ts.map +1 -1
  8. package/dist/components/chart-renderer/lib/registry.js +3 -1
  9. package/dist/components/chart-renderer/lib/registry.js.map +1 -1
  10. package/dist/components/kpi-widget/element/styles.d.ts.map +1 -1
  11. package/dist/components/kpi-widget/element/styles.js +268 -5
  12. package/dist/components/kpi-widget/element/styles.js.map +1 -1
  13. package/dist/components/kpi-widget/element/ui9000-kpi-widget.d.ts +10 -1
  14. package/dist/components/kpi-widget/element/ui9000-kpi-widget.d.ts.map +1 -1
  15. package/dist/components/kpi-widget/element/ui9000-kpi-widget.js +154 -27
  16. package/dist/components/kpi-widget/element/ui9000-kpi-widget.js.map +1 -1
  17. package/dist/components/kpi-widget/index.d.ts +1 -1
  18. package/dist/components/kpi-widget/index.d.ts.map +1 -1
  19. package/dist/components/kpi-widget/index.js +7 -4
  20. package/dist/components/kpi-widget/lib/extract.d.ts +5 -1
  21. package/dist/components/kpi-widget/lib/extract.d.ts.map +1 -1
  22. package/dist/components/kpi-widget/lib/extract.js +110 -34
  23. package/dist/components/kpi-widget/lib/extract.js.map +1 -1
  24. package/dist/components/kpi-widget/lib/format.d.ts +5 -0
  25. package/dist/components/kpi-widget/lib/format.d.ts.map +1 -1
  26. package/dist/components/kpi-widget/lib/format.js +10 -1
  27. package/dist/components/kpi-widget/lib/format.js.map +1 -1
  28. package/dist/components/kpi-widget/lib/grid.d.ts +5 -0
  29. package/dist/components/kpi-widget/lib/grid.d.ts.map +1 -1
  30. package/dist/components/kpi-widget/lib/grid.js +18 -0
  31. package/dist/components/kpi-widget/lib/grid.js.map +1 -1
  32. package/dist/components/kpi-widget/lib/index.d.ts +5 -5
  33. package/dist/components/kpi-widget/lib/index.d.ts.map +1 -1
  34. package/dist/components/kpi-widget/lib/normalize.d.ts +2 -0
  35. package/dist/components/kpi-widget/lib/normalize.d.ts.map +1 -1
  36. package/dist/components/kpi-widget/lib/normalize.js +73 -12
  37. package/dist/components/kpi-widget/lib/normalize.js.map +1 -1
  38. package/dist/components/kpi-widget/lib/types.d.ts +41 -0
  39. package/dist/components/kpi-widget/lib/types.d.ts.map +1 -1
  40. package/dist/components/kpi-widget/metadata.json.d.ts +1 -1
  41. package/dist/components/kpi-widget/metadata.json.js +1 -1
  42. package/dist/components/map-chart/metadata.json.d.ts +1 -1
  43. package/dist/components/map-chart/metadata.json.js +1 -1
  44. package/dist/components/map-chart/render/draw.d.ts.map +1 -1
  45. package/dist/components/map-chart/render/draw.js +2 -1
  46. package/dist/components/map-chart/render/draw.js.map +1 -1
  47. package/dist/components/partial-dependence-chart/element/styles.d.ts +2 -0
  48. package/dist/components/partial-dependence-chart/element/styles.d.ts.map +1 -0
  49. package/dist/components/partial-dependence-chart/element/styles.js +48 -0
  50. package/dist/components/partial-dependence-chart/element/styles.js.map +1 -0
  51. package/dist/components/partial-dependence-chart/element/ui9000-partial-dependence-chart.d.ts +30 -0
  52. package/dist/components/partial-dependence-chart/element/ui9000-partial-dependence-chart.d.ts.map +1 -0
  53. package/dist/components/partial-dependence-chart/element/ui9000-partial-dependence-chart.js +163 -0
  54. package/dist/components/partial-dependence-chart/element/ui9000-partial-dependence-chart.js.map +1 -0
  55. package/dist/components/partial-dependence-chart/index.d.ts +5 -0
  56. package/dist/components/partial-dependence-chart/index.d.ts.map +1 -0
  57. package/dist/components/partial-dependence-chart/index.js +18 -0
  58. package/dist/components/partial-dependence-chart/index.js.map +1 -0
  59. package/dist/components/partial-dependence-chart/lib/domain.d.ts +6 -0
  60. package/dist/components/partial-dependence-chart/lib/domain.d.ts.map +1 -0
  61. package/dist/components/partial-dependence-chart/lib/domain.js +16 -0
  62. package/dist/components/partial-dependence-chart/lib/domain.js.map +1 -0
  63. package/dist/components/partial-dependence-chart/lib/index.d.ts +5 -0
  64. package/dist/components/partial-dependence-chart/lib/index.d.ts.map +1 -0
  65. package/dist/components/partial-dependence-chart/lib/normalize.d.ts +4 -0
  66. package/dist/components/partial-dependence-chart/lib/normalize.d.ts.map +1 -0
  67. package/dist/components/partial-dependence-chart/lib/normalize.js +167 -0
  68. package/dist/components/partial-dependence-chart/lib/normalize.js.map +1 -0
  69. package/dist/components/partial-dependence-chart/lib/series.d.ts +15 -0
  70. package/dist/components/partial-dependence-chart/lib/series.d.ts.map +1 -0
  71. package/dist/components/partial-dependence-chart/lib/series.js +63 -0
  72. package/dist/components/partial-dependence-chart/lib/series.js.map +1 -0
  73. package/dist/components/partial-dependence-chart/lib/types.d.ts +50 -0
  74. package/dist/components/partial-dependence-chart/lib/types.d.ts.map +1 -0
  75. package/dist/components/partial-dependence-chart/metadata.json.d.ts +80 -0
  76. package/dist/components/partial-dependence-chart/metadata.json.js +42 -0
  77. package/dist/components/partial-dependence-chart/metadata.json.js.map +1 -0
  78. package/dist/components/partial-dependence-chart/render/draw.d.ts +34 -0
  79. package/dist/components/partial-dependence-chart/render/draw.d.ts.map +1 -0
  80. package/dist/components/partial-dependence-chart/render/draw.js +95 -0
  81. package/dist/components/partial-dependence-chart/render/draw.js.map +1 -0
  82. package/dist/components/partial-dependence-chart/render/index.d.ts +2 -0
  83. package/dist/components/partial-dependence-chart/render/index.d.ts.map +1 -0
  84. package/dist/index.d.ts +5 -3
  85. package/dist/index.d.ts.map +1 -1
  86. package/dist/index.js +25 -10
  87. package/dist/index.js.map +1 -1
  88. package/dist/lazy/index.d.ts +2 -1
  89. package/dist/lazy/index.d.ts.map +1 -1
  90. package/dist/lazy/index.js +8 -0
  91. package/dist/lazy/index.js.map +1 -1
  92. package/dist/lazy/partial-dependence-chart.d.ts +4 -0
  93. package/dist/lazy/partial-dependence-chart.d.ts.map +1 -0
  94. package/dist/lazy/partial-dependence-chart.js +5 -0
  95. package/dist/lazy/partial-dependence-chart.js.map +1 -0
  96. package/dist/utils/chart-helpers.d.ts +2 -0
  97. package/dist/utils/chart-helpers.d.ts.map +1 -1
  98. package/dist/utils/chart-helpers.js +15 -0
  99. package/dist/utils/chart-helpers.js.map +1 -1
  100. package/dist/utils/fusedash-visual.d.ts +12 -0
  101. package/dist/utils/fusedash-visual.d.ts.map +1 -1
  102. package/dist/utils/fusedash-visual.js +7 -0
  103. package/dist/utils/fusedash-visual.js.map +1 -1
  104. package/package.json +11 -2
  105. package/dist/node_modules/lit-html/directive.js +0 -28
  106. package/dist/node_modules/lit-html/directive.js.map +0 -1
  107. package/dist/node_modules/lit-html/directives/style-map.js +0 -37
  108. package/dist/node_modules/lit-html/directives/style-map.js.map +0 -1
  109. package/dist/node_modules/lit-html/lit-html.js +0 -231
  110. package/dist/node_modules/lit-html/lit-html.js.map +0 -1
@@ -1,4 +1,9 @@
1
1
  export declare const MIN_KPI_CELL_WIDTH = 90;
2
+ export declare const ADVANCED_KPI_VALUE_PERCENT = 25;
3
+ export declare const ADVANCED_KPI_CHART_PERCENT = 75;
4
+ export type AdvancedSplitLayout = 'horizontal' | 'stacked';
5
+ /** Port of client `getAdvancedSplitLayout` (KpiFlexibleComponent/styles). */
6
+ export declare function getAdvancedSplitLayout(width: number, height: number, previousLayout?: AdvancedSplitLayout): AdvancedSplitLayout;
2
7
  export declare const getPreferredKpiColumnCounts: (kpiCount: number) => number[];
3
8
  export declare const getKpiGridColumns: (containerWidth: number, kpiCount: number, minCellWidth?: number) => number;
4
9
  export type KpiGridScrollAxis = 'vertical' | 'horizontal' | 'both';
@@ -1 +1 @@
1
- {"version":3,"file":"grid.d.ts","sourceRoot":"","sources":["../../../../src/components/kpi-widget/lib/grid.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kBAAkB,KAAK,CAAC;AAErC,eAAO,MAAM,2BAA2B,GAAI,UAAU,MAAM,KAAG,MAAM,EAcpE,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC5B,gBAAgB,MAAM,EACtB,UAAU,MAAM,EAChB,eAAc,MAA2B,KACxC,MAWF,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,UAAU,GAAG,YAAY,GAAG,MAAM,CAAC;AAEnE,eAAO,MAAM,oBAAoB,GAC/B,aAAa,MAAM,EACnB,UAAU,MAAM,KACf,iBAUF,CAAC"}
1
+ {"version":3,"file":"grid.d.ts","sourceRoot":"","sources":["../../../../src/components/kpi-widget/lib/grid.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kBAAkB,KAAK,CAAC;AAErC,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAC7C,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAE7C,MAAM,MAAM,mBAAmB,GAAG,YAAY,GAAG,SAAS,CAAC;AAE3D,6EAA6E;AAC7E,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,cAAc,GAAE,mBAAkC,GACjD,mBAAmB,CAkBrB;AAED,eAAO,MAAM,2BAA2B,GAAI,UAAU,MAAM,KAAG,MAAM,EAcpE,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC5B,gBAAgB,MAAM,EACtB,UAAU,MAAM,EAChB,eAAc,MAA2B,KACxC,MAWF,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,UAAU,GAAG,YAAY,GAAG,MAAM,CAAC;AAEnE,eAAO,MAAM,oBAAoB,GAC/B,aAAa,MAAM,EACnB,UAAU,MAAM,KACf,iBAUF,CAAC"}
@@ -1,4 +1,20 @@
1
1
  const MIN_KPI_CELL_WIDTH = 90;
2
+ const ADVANCED_KPI_VALUE_PERCENT = 25;
3
+ function getAdvancedSplitLayout(width, height, previousLayout = "horizontal") {
4
+ if (width <= 0 || height <= 0) return previousLayout;
5
+ const valueColWidth = width * (ADVANCED_KPI_VALUE_PERCENT / 100);
6
+ const aspectRatio = height / width;
7
+ if (previousLayout === "stacked") {
8
+ if (valueColWidth >= 64 && width >= 200 && aspectRatio <= 1.45) {
9
+ return "horizontal";
10
+ }
11
+ return "stacked";
12
+ }
13
+ if (valueColWidth < 52 || width < 170 || aspectRatio > 1.62) {
14
+ return "stacked";
15
+ }
16
+ return "horizontal";
17
+ }
2
18
  const getPreferredKpiColumnCounts = (kpiCount) => {
3
19
  if (kpiCount <= 1) return [1];
4
20
  const divisors = [];
@@ -30,7 +46,9 @@ const getKpiGridScrollAxis = (gridColumns, kpiCount) => {
30
46
  return "both";
31
47
  };
32
48
  export {
49
+ ADVANCED_KPI_VALUE_PERCENT,
33
50
  MIN_KPI_CELL_WIDTH,
51
+ getAdvancedSplitLayout,
34
52
  getKpiGridColumns,
35
53
  getKpiGridScrollAxis,
36
54
  getPreferredKpiColumnCounts
@@ -1 +1 @@
1
- {"version":3,"file":"grid.js","sources":["../../../../src/components/kpi-widget/lib/grid.ts"],"sourcesContent":["export const MIN_KPI_CELL_WIDTH = 90;\n\nexport const getPreferredKpiColumnCounts = (kpiCount: number): number[] => {\n if (kpiCount <= 1) return [1];\n\n const divisors: number[] = [];\n for (let i = kpiCount; i >= 1; i -= 1) {\n if (kpiCount % i === 0) divisors.push(i);\n }\n\n if (kpiCount % 2 !== 0 && kpiCount > 2 && !divisors.includes(2)) {\n divisors.push(2);\n divisors.sort((a, b) => b - a);\n }\n\n return divisors;\n};\n\nexport const getKpiGridColumns = (\n containerWidth: number,\n kpiCount: number,\n minCellWidth: number = MIN_KPI_CELL_WIDTH,\n): number => {\n if (kpiCount <= 1) return 1;\n if (containerWidth <= 0) return 1;\n\n const maxColumns = Math.max(\n 1,\n Math.min(kpiCount, Math.floor(containerWidth / minCellWidth)),\n );\n\n const preferred = getPreferredKpiColumnCounts(kpiCount);\n return preferred.find((cols) => cols <= maxColumns) ?? 1;\n};\n\nexport type KpiGridScrollAxis = 'vertical' | 'horizontal' | 'both';\n\nexport const getKpiGridScrollAxis = (\n gridColumns: number,\n kpiCount: number,\n): KpiGridScrollAxis => {\n if (kpiCount <= 1) return 'vertical';\n\n const columns = Math.max(1, gridColumns);\n const gridRows = Math.ceil(kpiCount / columns);\n\n if (columns === 1) return 'vertical';\n if (gridRows === 1) return 'horizontal';\n\n return 'both';\n};\n"],"names":[],"mappings":"AAAO,MAAM,qBAAqB;AAE3B,MAAM,8BAA8B,CAAC,aAA+B;AACzE,MAAI,YAAY,EAAG,QAAO,CAAC,CAAC;AAE5B,QAAM,WAAqB,CAAA;AAC3B,WAAS,IAAI,UAAU,KAAK,GAAG,KAAK,GAAG;AACrC,QAAI,WAAW,MAAM,EAAG,UAAS,KAAK,CAAC;AAAA,EACzC;AAEA,MAAI,WAAW,MAAM,KAAK,WAAW,KAAK,CAAC,SAAS,SAAS,CAAC,GAAG;AAC/D,aAAS,KAAK,CAAC;AACf,aAAS,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC;AAAA,EAC/B;AAEA,SAAO;AACT;AAEO,MAAM,oBAAoB,CAC/B,gBACA,UACA,eAAuB,uBACZ;AACX,MAAI,YAAY,EAAG,QAAO;AAC1B,MAAI,kBAAkB,EAAG,QAAO;AAEhC,QAAM,aAAa,KAAK;AAAA,IACtB;AAAA,IACA,KAAK,IAAI,UAAU,KAAK,MAAM,iBAAiB,YAAY,CAAC;AAAA,EAAA;AAG9D,QAAM,YAAY,4BAA4B,QAAQ;AACtD,SAAO,UAAU,KAAK,CAAC,SAAS,QAAQ,UAAU,KAAK;AACzD;AAIO,MAAM,uBAAuB,CAClC,aACA,aACsB;AACtB,MAAI,YAAY,EAAG,QAAO;AAE1B,QAAM,UAAU,KAAK,IAAI,GAAG,WAAW;AACvC,QAAM,WAAW,KAAK,KAAK,WAAW,OAAO;AAE7C,MAAI,YAAY,EAAG,QAAO;AAC1B,MAAI,aAAa,EAAG,QAAO;AAE3B,SAAO;AACT;"}
1
+ {"version":3,"file":"grid.js","sources":["../../../../src/components/kpi-widget/lib/grid.ts"],"sourcesContent":["export const MIN_KPI_CELL_WIDTH = 90;\n\nexport const ADVANCED_KPI_VALUE_PERCENT = 25;\nexport const ADVANCED_KPI_CHART_PERCENT = 75;\n\nexport type AdvancedSplitLayout = 'horizontal' | 'stacked';\n\n/** Port of client `getAdvancedSplitLayout` (KpiFlexibleComponent/styles). */\nexport function getAdvancedSplitLayout(\n width: number,\n height: number,\n previousLayout: AdvancedSplitLayout = 'horizontal',\n): AdvancedSplitLayout {\n if (width <= 0 || height <= 0) return previousLayout;\n\n const valueColWidth = width * (ADVANCED_KPI_VALUE_PERCENT / 100);\n const aspectRatio = height / width;\n\n if (previousLayout === 'stacked') {\n if (valueColWidth >= 64 && width >= 200 && aspectRatio <= 1.45) {\n return 'horizontal';\n }\n return 'stacked';\n }\n\n if (valueColWidth < 52 || width < 170 || aspectRatio > 1.62) {\n return 'stacked';\n }\n\n return 'horizontal';\n}\n\nexport const getPreferredKpiColumnCounts = (kpiCount: number): number[] => {\n if (kpiCount <= 1) return [1];\n\n const divisors: number[] = [];\n for (let i = kpiCount; i >= 1; i -= 1) {\n if (kpiCount % i === 0) divisors.push(i);\n }\n\n if (kpiCount % 2 !== 0 && kpiCount > 2 && !divisors.includes(2)) {\n divisors.push(2);\n divisors.sort((a, b) => b - a);\n }\n\n return divisors;\n};\n\nexport const getKpiGridColumns = (\n containerWidth: number,\n kpiCount: number,\n minCellWidth: number = MIN_KPI_CELL_WIDTH,\n): number => {\n if (kpiCount <= 1) return 1;\n if (containerWidth <= 0) return 1;\n\n const maxColumns = Math.max(\n 1,\n Math.min(kpiCount, Math.floor(containerWidth / minCellWidth)),\n );\n\n const preferred = getPreferredKpiColumnCounts(kpiCount);\n return preferred.find((cols) => cols <= maxColumns) ?? 1;\n};\n\nexport type KpiGridScrollAxis = 'vertical' | 'horizontal' | 'both';\n\nexport const getKpiGridScrollAxis = (\n gridColumns: number,\n kpiCount: number,\n): KpiGridScrollAxis => {\n if (kpiCount <= 1) return 'vertical';\n\n const columns = Math.max(1, gridColumns);\n const gridRows = Math.ceil(kpiCount / columns);\n\n if (columns === 1) return 'vertical';\n if (gridRows === 1) return 'horizontal';\n\n return 'both';\n};\n"],"names":[],"mappings":"AAAO,MAAM,qBAAqB;AAE3B,MAAM,6BAA6B;AAMnC,SAAS,uBACd,OACA,QACA,iBAAsC,cACjB;AACrB,MAAI,SAAS,KAAK,UAAU,EAAG,QAAO;AAEtC,QAAM,gBAAgB,SAAS,6BAA6B;AAC5D,QAAM,cAAc,SAAS;AAE7B,MAAI,mBAAmB,WAAW;AAChC,QAAI,iBAAiB,MAAM,SAAS,OAAO,eAAe,MAAM;AAC9D,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAEA,MAAI,gBAAgB,MAAM,QAAQ,OAAO,cAAc,MAAM;AAC3D,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEO,MAAM,8BAA8B,CAAC,aAA+B;AACzE,MAAI,YAAY,EAAG,QAAO,CAAC,CAAC;AAE5B,QAAM,WAAqB,CAAA;AAC3B,WAAS,IAAI,UAAU,KAAK,GAAG,KAAK,GAAG;AACrC,QAAI,WAAW,MAAM,EAAG,UAAS,KAAK,CAAC;AAAA,EACzC;AAEA,MAAI,WAAW,MAAM,KAAK,WAAW,KAAK,CAAC,SAAS,SAAS,CAAC,GAAG;AAC/D,aAAS,KAAK,CAAC;AACf,aAAS,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC;AAAA,EAC/B;AAEA,SAAO;AACT;AAEO,MAAM,oBAAoB,CAC/B,gBACA,UACA,eAAuB,uBACZ;AACX,MAAI,YAAY,EAAG,QAAO;AAC1B,MAAI,kBAAkB,EAAG,QAAO;AAEhC,QAAM,aAAa,KAAK;AAAA,IACtB;AAAA,IACA,KAAK,IAAI,UAAU,KAAK,MAAM,iBAAiB,YAAY,CAAC;AAAA,EAAA;AAG9D,QAAM,YAAY,4BAA4B,QAAQ;AACtD,SAAO,UAAU,KAAK,CAAC,SAAS,QAAQ,UAAU,KAAK;AACzD;AAIO,MAAM,uBAAuB,CAClC,aACA,aACsB;AACtB,MAAI,YAAY,EAAG,QAAO;AAE1B,QAAM,UAAU,KAAK,IAAI,GAAG,WAAW;AACvC,QAAM,WAAW,KAAK,KAAK,WAAW,OAAO;AAE7C,MAAI,YAAY,EAAG,QAAO;AAC1B,MAAI,aAAa,EAAG,QAAO;AAE3B,SAAO;AACT;"}
@@ -1,6 +1,6 @@
1
- export { normalizeKpiData } from './normalize.js';
2
- export { extractCardsFromKpi } from './extract.js';
3
- export { formatKpiValue } from './format.js';
4
- export { getKpiGridColumns, getKpiGridScrollAxis, MIN_KPI_CELL_WIDTH, type KpiGridScrollAxis, } from './grid.js';
5
- export type { KpiCardModel, KpiValueLabel, KpiWidgetData, KpiWidgetModel, RawKpiItem, } from './types.js';
1
+ export { normalizeKpiData, extractGroupId } from './normalize.js';
2
+ export { extractCardsFromKpi, isAdvancedKpiItem, visualisationChartType } from './extract.js';
3
+ export { formatKpiValue, splitFormattedKpiValue } from './format.js';
4
+ export { getKpiGridColumns, getKpiGridScrollAxis, getAdvancedSplitLayout, MIN_KPI_CELL_WIDTH, ADVANCED_KPI_VALUE_PERCENT, ADVANCED_KPI_CHART_PERCENT, type KpiGridScrollAxis, type AdvancedSplitLayout, } from './grid.js';
5
+ export type { KpiCardModel, KpiCardRole, KpiStatusBadge, KpiStatusVariant, KpiValueLabel, KpiWidgetData, KpiWidgetLayout, KpiWidgetModel, RawKpiItem, RawKpiVisualisation, } from './types.js';
6
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/kpi-widget/lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,kBAAkB,EAClB,KAAK,iBAAiB,GACvB,MAAM,WAAW,CAAC;AACnB,YAAY,EACV,YAAY,EACZ,aAAa,EACb,aAAa,EACb,cAAc,EACd,UAAU,GACX,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/kpi-widget/lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAC9F,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,sBAAsB,EACtB,kBAAkB,EAClB,0BAA0B,EAC1B,0BAA0B,EAC1B,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,GACzB,MAAM,WAAW,CAAC;AACnB,YAAY,EACV,YAAY,EACZ,WAAW,EACX,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,eAAe,EACf,cAAc,EACd,UAAU,EACV,mBAAmB,GACpB,MAAM,YAAY,CAAC"}
@@ -1,4 +1,6 @@
1
1
  import { KpiWidgetData, KpiWidgetModel } from './types.js';
2
+ /** Client `extractGroupId` — groupName is `{label}-group-kpi-ids-{id}`. */
3
+ export declare function extractGroupId(value?: string | null): string;
2
4
  /** Normalize chat / FuseDash KPI payloads into display cards. */
3
5
  export declare function normalizeKpiData(input: KpiWidgetData): KpiWidgetModel;
4
6
  //# sourceMappingURL=normalize.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../../../../src/components/kpi-widget/lib/normalize.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAc,MAAM,YAAY,CAAC;AAiB5E,iEAAiE;AACjE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,aAAa,GAAG,cAAc,CAwBrE"}
1
+ {"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../../../../src/components/kpi-widget/lib/normalize.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAc,MAAM,YAAY,CAAC;AAiB5E,2EAA2E;AAC3E,wBAAgB,cAAc,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAE5D;AAgFD,iEAAiE;AACjE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,aAAa,GAAG,cAAc,CAyBrE"}
@@ -1,34 +1,95 @@
1
- import { extractCardsFromKpi } from "./extract.js";
2
- const EMPTY = { cards: [] };
1
+ import { isAdvancedKpiItem, extractCardsFromKpi } from "./extract.js";
2
+ const EMPTY = { layout: "empty", cards: [], supporting: [] };
3
3
  function isRawKpiItem(input) {
4
- return input != null && typeof input === "object" && !Array.isArray(input) && ("data" in input || "column" in input);
4
+ return input != null && typeof input === "object" && !Array.isArray(input) && ("data" in input || "column" in input || "type" in input);
5
5
  }
6
- function fromItems(items) {
7
- return { cards: items.flatMap((item) => extractCardsFromKpi(item)) };
6
+ function isNormalizedModel(input) {
7
+ return Array.isArray(input.cards) && "layout" in input;
8
+ }
9
+ function extractGroupId(value) {
10
+ var _a;
11
+ return ((_a = value == null ? void 0 : value.split("-group-kpi-ids-")) == null ? void 0 : _a[0]) ?? "";
12
+ }
13
+ function sortItems(items) {
14
+ return [...items].sort((a, b) => {
15
+ if (isAdvancedKpiItem(a) && !isAdvancedKpiItem(b)) return -1;
16
+ if (!isAdvancedKpiItem(a) && isAdvancedKpiItem(b)) return 1;
17
+ return 0;
18
+ });
19
+ }
20
+ function footerFrom(items) {
21
+ const first = items[0];
22
+ return {
23
+ target: first == null ? void 0 : first.target,
24
+ showTimestamp: first == null ? void 0 : first.showTimestamp,
25
+ updatedAt: first == null ? void 0 : first.updatedAt
26
+ };
27
+ }
28
+ function sectionTitle(items, advanced, topName) {
29
+ var _a, _b;
30
+ if (advanced) return void 0;
31
+ if (items.length === 1) return (_a = items[0]) == null ? void 0 : _a.name;
32
+ const grouped = extractGroupId((_b = items[0]) == null ? void 0 : _b.groupName);
33
+ if (grouped) return grouped;
34
+ return (topName == null ? void 0 : topName.trim()) || void 0;
35
+ }
36
+ function buildFromItems(items, topName) {
37
+ if (!items.length) return EMPTY;
38
+ const sorted = sortItems(items);
39
+ const advancedIndex = sorted.findIndex(isAdvancedKpiItem);
40
+ const advanced = advancedIndex >= 0;
41
+ const footer = footerFrom(sorted);
42
+ if (advanced) {
43
+ const mainItem = sorted[advancedIndex];
44
+ const mainCards = extractCardsFromKpi(mainItem);
45
+ const main = mainCards[0];
46
+ const supporting = sorted.filter((_, i) => i !== advancedIndex).flatMap((item) => extractCardsFromKpi(item));
47
+ const viz = mainItem.visualisation && typeof mainItem.visualisation === "object" ? mainItem.visualisation : null;
48
+ return {
49
+ layout: "advanced",
50
+ title: sectionTitle(sorted, true, topName),
51
+ cards: main ? [main, ...supporting] : supporting,
52
+ main,
53
+ supporting,
54
+ visualisation: viz,
55
+ ...footer
56
+ };
57
+ }
58
+ const cards = sorted.flatMap((item) => extractCardsFromKpi(item));
59
+ const hideNames = sorted.length === 1 && cards.length >= 1;
60
+ const titledCards = hideNames ? cards.map((card) => ({ ...card, hideName: true })) : cards;
61
+ const layout = titledCards.length === 0 ? "empty" : titledCards.length === 1 ? "single" : "grid";
62
+ return {
63
+ layout,
64
+ title: sectionTitle(sorted, false, topName),
65
+ cards: titledCards,
66
+ supporting: [],
67
+ ...footer
68
+ };
8
69
  }
9
70
  function normalizeKpiData(input) {
10
71
  if (!input) return EMPTY;
11
72
  if (Array.isArray(input)) {
12
73
  if (!input.length) return EMPTY;
13
- return fromItems(input);
74
+ return buildFromItems(input);
14
75
  }
15
76
  if (typeof input === "object") {
16
- if (Array.isArray(input.cards)) {
17
- return input;
18
- }
77
+ if (isNormalizedModel(input)) return input;
78
+ const topName = typeof input.name === "string" ? input.name : void 0;
19
79
  if (Array.isArray(input.items)) {
20
- return fromItems(input.items);
80
+ return buildFromItems(input.items, topName);
21
81
  }
22
82
  if (Array.isArray(input.kpis)) {
23
- return fromItems(input.kpis);
83
+ return buildFromItems(input.kpis, topName);
24
84
  }
25
85
  if (isRawKpiItem(input)) {
26
- return { cards: extractCardsFromKpi(input) };
86
+ return buildFromItems([input], topName);
27
87
  }
28
88
  }
29
89
  return EMPTY;
30
90
  }
31
91
  export {
92
+ extractGroupId,
32
93
  normalizeKpiData
33
94
  };
34
95
  //# sourceMappingURL=normalize.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"normalize.js","sources":["../../../../src/components/kpi-widget/lib/normalize.ts"],"sourcesContent":["import { extractCardsFromKpi } from './extract.js';\nimport type { KpiWidgetData, KpiWidgetModel, RawKpiItem } from './types.js';\n\nconst EMPTY: KpiWidgetModel = { cards: [] };\n\nfunction isRawKpiItem(input: unknown): input is RawKpiItem {\n return (\n input != null &&\n typeof input === 'object' &&\n !Array.isArray(input) &&\n ('data' in (input as object) || 'column' in (input as object))\n );\n}\n\nfunction fromItems(items: RawKpiItem[]): KpiWidgetModel {\n return { cards: items.flatMap((item) => extractCardsFromKpi(item)) };\n}\n\n/** Normalize chat / FuseDash KPI payloads into display cards. */\nexport function normalizeKpiData(input: KpiWidgetData): KpiWidgetModel {\n if (!input) return EMPTY;\n\n if (Array.isArray(input)) {\n if (!input.length) return EMPTY;\n return fromItems(input);\n }\n\n if (typeof input === 'object') {\n if (Array.isArray((input as KpiWidgetModel).cards)) {\n return input as KpiWidgetModel;\n }\n if (Array.isArray((input as { items?: RawKpiItem[] }).items)) {\n return fromItems((input as { items: RawKpiItem[] }).items);\n }\n if (Array.isArray((input as { kpis?: RawKpiItem[] }).kpis)) {\n return fromItems((input as { kpis: RawKpiItem[] }).kpis);\n }\n if (isRawKpiItem(input)) {\n return { cards: extractCardsFromKpi(input) };\n }\n }\n\n return EMPTY;\n}\n"],"names":[],"mappings":";AAGA,MAAM,QAAwB,EAAE,OAAO,GAAC;AAExC,SAAS,aAAa,OAAqC;AACzD,SACE,SAAS,QACT,OAAO,UAAU,YACjB,CAAC,MAAM,QAAQ,KAAK,MACnB,UAAW,SAAoB,YAAa;AAEjD;AAEA,SAAS,UAAU,OAAqC;AACtD,SAAO,EAAE,OAAO,MAAM,QAAQ,CAAC,SAAS,oBAAoB,IAAI,CAAC,EAAA;AACnE;AAGO,SAAS,iBAAiB,OAAsC;AACrE,MAAI,CAAC,MAAO,QAAO;AAEnB,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,QAAI,CAAC,MAAM,OAAQ,QAAO;AAC1B,WAAO,UAAU,KAAK;AAAA,EACxB;AAEA,MAAI,OAAO,UAAU,UAAU;AAC7B,QAAI,MAAM,QAAS,MAAyB,KAAK,GAAG;AAClD,aAAO;AAAA,IACT;AACA,QAAI,MAAM,QAAS,MAAmC,KAAK,GAAG;AAC5D,aAAO,UAAW,MAAkC,KAAK;AAAA,IAC3D;AACA,QAAI,MAAM,QAAS,MAAkC,IAAI,GAAG;AAC1D,aAAO,UAAW,MAAiC,IAAI;AAAA,IACzD;AACA,QAAI,aAAa,KAAK,GAAG;AACvB,aAAO,EAAE,OAAO,oBAAoB,KAAK,EAAA;AAAA,IAC3C;AAAA,EACF;AAEA,SAAO;AACT;"}
1
+ {"version":3,"file":"normalize.js","sources":["../../../../src/components/kpi-widget/lib/normalize.ts"],"sourcesContent":["import { extractCardsFromKpi, isAdvancedKpiItem } from './extract.js';\nimport type { KpiWidgetData, KpiWidgetModel, RawKpiItem } from './types.js';\n\nconst EMPTY: KpiWidgetModel = { layout: 'empty', cards: [], supporting: [] };\n\nfunction isRawKpiItem(input: unknown): input is RawKpiItem {\n return (\n input != null &&\n typeof input === 'object' &&\n !Array.isArray(input) &&\n ('data' in (input as object) || 'column' in (input as object) || 'type' in (input as object))\n );\n}\n\nfunction isNormalizedModel(input: object): input is KpiWidgetModel {\n return Array.isArray((input as KpiWidgetModel).cards) && 'layout' in input;\n}\n\n/** Client `extractGroupId` — groupName is `{label}-group-kpi-ids-{id}`. */\nexport function extractGroupId(value?: string | null): string {\n return value?.split('-group-kpi-ids-')?.[0] ?? '';\n}\n\nfunction sortItems(items: RawKpiItem[]): RawKpiItem[] {\n return [...items].sort((a, b) => {\n if (isAdvancedKpiItem(a) && !isAdvancedKpiItem(b)) return -1;\n if (!isAdvancedKpiItem(a) && isAdvancedKpiItem(b)) return 1;\n return 0;\n });\n}\n\nfunction footerFrom(items: RawKpiItem[]): Pick<\n KpiWidgetModel,\n 'target' | 'showTimestamp' | 'updatedAt'\n> {\n const first = items[0];\n return {\n target: first?.target,\n showTimestamp: first?.showTimestamp,\n updatedAt: first?.updatedAt,\n };\n}\n\nfunction sectionTitle(\n items: RawKpiItem[],\n advanced: boolean,\n topName?: string,\n): string | undefined {\n if (advanced) return undefined;\n if (items.length === 1) return items[0]?.name;\n const grouped = extractGroupId(items[0]?.groupName);\n if (grouped) return grouped;\n return topName?.trim() || undefined;\n}\n\nfunction buildFromItems(items: RawKpiItem[], topName?: string): KpiWidgetModel {\n if (!items.length) return EMPTY;\n const sorted = sortItems(items);\n const advancedIndex = sorted.findIndex(isAdvancedKpiItem);\n const advanced = advancedIndex >= 0;\n const footer = footerFrom(sorted);\n\n if (advanced) {\n const mainItem = sorted[advancedIndex]!;\n const mainCards = extractCardsFromKpi(mainItem);\n const main = mainCards[0];\n const supporting = sorted\n .filter((_, i) => i !== advancedIndex)\n .flatMap((item) => extractCardsFromKpi(item));\n const viz =\n mainItem.visualisation && typeof mainItem.visualisation === 'object'\n ? (mainItem.visualisation as Record<string, unknown>)\n : null;\n return {\n layout: 'advanced',\n title: sectionTitle(sorted, true, topName),\n cards: main ? [main, ...supporting] : supporting,\n main,\n supporting,\n visualisation: viz,\n ...footer,\n };\n }\n\n const cards = sorted.flatMap((item) => extractCardsFromKpi(item));\n const hideNames = sorted.length === 1 && cards.length >= 1;\n const titledCards = hideNames\n ? cards.map((card) => ({ ...card, hideName: true }))\n : cards;\n const layout: KpiWidgetModel['layout'] =\n titledCards.length === 0 ? 'empty' : titledCards.length === 1 ? 'single' : 'grid';\n\n return {\n layout,\n title: sectionTitle(sorted, false, topName),\n cards: titledCards,\n supporting: [],\n ...footer,\n };\n}\n\n/** Normalize chat / FuseDash KPI payloads into display cards. */\nexport function normalizeKpiData(input: KpiWidgetData): KpiWidgetModel {\n if (!input) return EMPTY;\n\n if (Array.isArray(input)) {\n if (!input.length) return EMPTY;\n return buildFromItems(input);\n }\n\n if (typeof input === 'object') {\n if (isNormalizedModel(input)) return input;\n const topName = typeof (input as { name?: unknown }).name === 'string'\n ? (input as { name: string }).name\n : undefined;\n if (Array.isArray((input as { items?: RawKpiItem[] }).items)) {\n return buildFromItems((input as { items: RawKpiItem[] }).items, topName);\n }\n if (Array.isArray((input as { kpis?: RawKpiItem[] }).kpis)) {\n return buildFromItems((input as { kpis: RawKpiItem[] }).kpis, topName);\n }\n if (isRawKpiItem(input)) {\n return buildFromItems([input], topName);\n }\n }\n\n return EMPTY;\n}\n"],"names":[],"mappings":"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"}
@@ -2,25 +2,64 @@ export interface KpiValueLabel {
2
2
  position: 'left' | 'right';
3
3
  text: string;
4
4
  }
5
+ export type KpiStatusVariant = 'Good' | 'Low' | 'Normal' | 'OnTarget' | 'OffTarget' | 'Mission';
6
+ export interface KpiStatusBadge {
7
+ text: string;
8
+ variant: KpiStatusVariant;
9
+ }
10
+ export type KpiCardRole = 'single' | 'grid' | 'main' | 'supporting';
5
11
  export interface KpiCardModel {
6
12
  id: string;
7
13
  name: string;
8
14
  value: string;
15
+ suffix?: string;
9
16
  indicator?: string;
10
17
  subtitle?: string;
11
18
  label?: KpiValueLabel;
19
+ status?: KpiStatusBadge;
20
+ showPercentage?: boolean;
21
+ hideName?: boolean;
12
22
  }
23
+ export type KpiWidgetLayout = 'empty' | 'single' | 'grid' | 'advanced';
13
24
  export interface KpiWidgetModel {
25
+ layout: KpiWidgetLayout;
26
+ title?: string;
14
27
  cards: KpiCardModel[];
28
+ main?: KpiCardModel;
29
+ supporting: KpiCardModel[];
30
+ visualisation?: Record<string, unknown> | null;
31
+ target?: string;
32
+ showTimestamp?: boolean;
33
+ updatedAt?: string;
34
+ }
35
+ export interface RawKpiVisualisation {
36
+ chartType?: string;
37
+ chart_type?: string;
38
+ name?: string;
39
+ data?: unknown[];
40
+ [key: string]: unknown;
15
41
  }
16
42
  export interface RawKpiItem {
17
43
  id?: string;
18
44
  name?: string;
19
45
  type?: string;
46
+ variant?: string;
20
47
  column?: string;
21
48
  aggregations?: string;
22
49
  groupBy?: string;
50
+ groupName?: string;
23
51
  data?: unknown[];
52
+ status?: string;
53
+ target?: string;
54
+ showTimestamp?: boolean;
55
+ showPercentage?: boolean;
56
+ showVisualisation?: boolean;
57
+ supportingKpis?: boolean;
58
+ visualisation?: RawKpiVisualisation | null;
59
+ updatedAt?: string;
60
+ kpiKind?: 'mission' | 'goal' | string;
61
+ targetStatus?: 'on_target' | 'off_target' | string;
62
+ score?: number;
24
63
  axisDetails?: Record<string, {
25
64
  label?: string;
26
65
  measure_unit_type?: string;
@@ -32,5 +71,7 @@ export type KpiWidgetData = RawKpiItem | RawKpiItem[] | {
32
71
  items?: RawKpiItem[];
33
72
  kpis?: RawKpiItem[];
34
73
  chartType?: string;
74
+ name?: string;
75
+ count?: number;
35
76
  } | KpiWidgetModel | null | undefined;
36
77
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/components/kpi-widget/lib/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,YAAY,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAClB,MAAM,EACN;QACE,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,mBAAmB,CAAC,EAAE,MAAM,CAAC;KAC9B,CACF,CAAC;CACH;AAED,MAAM,MAAM,aAAa,GACrB,UAAU,GACV,UAAU,EAAE,GACZ;IAAE,KAAK,CAAC,EAAE,UAAU,EAAE,CAAC;IAAC,IAAI,CAAC,EAAE,UAAU,EAAE,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GACjE,cAAc,GACd,IAAI,GACJ,SAAS,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/components/kpi-widget/lib/types.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,7 @@ declare const _default: {
2
2
  "id": "kpi-widget",
3
3
  "tag": "ui9000-kpi-widget",
4
4
  "title": "KPI Widget",
5
- "description": "Chat-optimized KPI cards (single_value grid and high/low_overall) — HTML/Lit, no Redux.",
5
+ "description": "Chat-optimized KPI cards — client types (single_value, trend, overall, comparison, high/low*) and advanced (nested chart + supporting KPIs). HTML/Lit, no Redux.",
6
6
  "chartTypeKeys": ["KPI", "KPIs"],
7
7
  "source": "client/libs/shared/components/src/Widgets/CustomWidget/components/KPIWidget/",
8
8
  "stack": "lit",
@@ -1,7 +1,7 @@
1
1
  const id = "kpi-widget";
2
2
  const tag = "ui9000-kpi-widget";
3
3
  const title = "KPI Widget";
4
- const description = "Chat-optimized KPI cards (single_value grid and high/low_overall) — HTML/Lit, no Redux.";
4
+ const description = "Chat-optimized KPI cards — client types (single_value, trend, overall, comparison, high/low*) and advanced (nested chart + supporting KPIs). HTML/Lit, no Redux.";
5
5
  const chartTypeKeys = ["KPI", "KPIs"];
6
6
  const source = "client/libs/shared/components/src/Widgets/CustomWidget/components/KPIWidget/";
7
7
  const stack = "lit";
@@ -12,7 +12,7 @@ declare const _default: {
12
12
  "host": "mcp-chat",
13
13
  "notFor": "fusedash-editor",
14
14
  "mapsExcluded": false,
15
- "hostReady": false,
15
+ "hostReady": true,
16
16
  "requires": ["mapbox-token", "geojson", "pmtiles"]
17
17
  },
18
18
  "allowedActions": ["hover", "pan", "zoom", "resize"],
@@ -7,7 +7,7 @@ const source = "client/libs/shared/components/src/Widgets/MapBox/";
7
7
  const stack = "mapbox-gl";
8
8
  const lazyImport = "@fusedashlabs/widgets/lazy/map-chart";
9
9
  const entry = "@fusedashlabs/widgets/map-chart";
10
- const usageConditions = { "host": "mcp-chat", "notFor": "fusedash-editor", "mapsExcluded": false, "hostReady": false, "requires": ["mapbox-token", "geojson", "pmtiles"] };
10
+ const usageConditions = { "host": "mcp-chat", "notFor": "fusedash-editor", "mapsExcluded": false, "hostReady": true, "requires": ["mapbox-token", "geojson", "pmtiles"] };
11
11
  const allowedActions = ["hover", "pan", "zoom", "resize"];
12
12
  const propsSchema = { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "data": { "oneOf": [{ "type": "object", "description": "FuseDash WidgetItem-shaped map payload (layers[].data + geospatialData).", "properties": { "name": { "type": "string" }, "chartType": { "type": "string", "const": "mapChart" }, "layers": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string" }, "visualisationType": { "type": "string", "enum": ["choropleth", "bubbles", "spike", "markers"] }, "geospatialData": { "type": "array", "items": { "type": "string" } }, "arrangeByMetric": { "type": "array", "items": { "type": "string" } }, "data": { "type": "array", "items": { "type": "object" } } } } } } }, { "type": "array", "description": "Chat rows { label, value } joined as a country choropleth.", "items": { "type": "object", "required": ["label", "value"], "properties": { "label": { "type": "string" }, "value": { "type": "number" } } } }] }, "chart-title": { "type": "string" }, "show-header": { "type": "boolean", "default": true }, "show-legend": { "type": "boolean", "default": true }, "show-tooltip": { "type": "boolean", "default": true }, "mapbox-token": { "type": "string" }, "geojson-base-url": { "type": "string", "description": "Base URL that serves {country,state,county,city,province}.json centroid FeatureCollections used for the data-join / bubbles / spikes." }, "pmtiles-base-url": { "type": "string", "default": "/pmtiles", "description": "Base URL that serves world-countries.pmtiles (and other admin archives). Choropleth fills use these vector tiles — the GeoJSON files are centroids, not polygons." } }, "required": ["data"] };
13
13
  const mapChartMeta = {
@@ -1 +1 @@
1
- {"version":3,"file":"draw.d.ts","sourceRoot":"","sources":["../../../../src/components/map-chart/render/draw.ts"],"names":[],"mappings":"AAYA,OAAO,EAIL,KAAK,WAAW,EACjB,MAAM,kBAAkB,CAAC;AAQ1B,OAAO,KAAK,EAA8B,aAAa,EAAiB,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE1G,MAAM,MAAM,OAAO,GAAG,OAAO,GAAG,MAAM,CAAC;AAEvC,MAAM,MAAM,qBAAqB,GAAG;IAClC,KAAK,EAAE,QAAQ,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACtC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,KAAK,IAAI,CAAC;CACjD,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;IAC5C,WAAW,EAAE,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,KAAK,IAAI,CAAC;CACvF,CAAC;AAmDF,wBAAgB,YAAY,CAAC,SAAS,EAAE,WAAW,GAAG,IAAI,CAGzD;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,WAAW,GAAG,OAAO,CAK9D;AAED,wBAAsB,cAAc,CAClC,SAAS,EAAE,WAAW,EACtB,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAwGpC"}
1
+ {"version":3,"file":"draw.d.ts","sourceRoot":"","sources":["../../../../src/components/map-chart/render/draw.ts"],"names":[],"mappings":"AAYA,OAAO,EAIL,KAAK,WAAW,EACjB,MAAM,kBAAkB,CAAC;AAQ1B,OAAO,KAAK,EAA8B,aAAa,EAAiB,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE1G,MAAM,MAAM,OAAO,GAAG,OAAO,GAAG,MAAM,CAAC;AAEvC,MAAM,MAAM,qBAAqB,GAAG;IAClC,KAAK,EAAE,QAAQ,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACtC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,KAAK,IAAI,CAAC;CACjD,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;IAC5C,WAAW,EAAE,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,KAAK,IAAI,CAAC;CACvF,CAAC;AAmDF,wBAAgB,YAAY,CAAC,SAAS,EAAE,WAAW,GAAG,IAAI,CAGzD;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,WAAW,GAAG,OAAO,CAK9D;AAED,wBAAsB,cAAc,CAClC,SAAS,EAAE,WAAW,EACtB,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CA2GpC"}
@@ -24,7 +24,8 @@ async function renderMapChart(container, options) {
24
24
  if (!options.token) return null;
25
25
  let mapbox;
26
26
  try {
27
- mapbox = await import("mapbox-gl");
27
+ const runtime = globalThis.mapboxgl;
28
+ mapbox = runtime ? { default: runtime } : await import("mapbox-gl");
28
29
  } catch {
29
30
  return null;
30
31
  }
@@ -1 +1 @@
1
- {"version":3,"file":"draw.js","sources":["../../../../src/components/map-chart/render/draw.ts"],"sourcesContent":["import {\n BUBBLE_RADIUS_STEPS,\n MAP_STYLES,\n MAPBOX_CSS_HREF,\n UNMATCHED_FILL,\n sanitizeKey,\n type MapVisualisation,\n} from '../lib/constants.js';\nimport { collectionBBox } from '../lib/domain.js';\nimport { darkenColor, hexToRgba } from '../lib/format.js';\nimport { getRegionIdFromFeatureProperties } from '../lib/geo-index.js';\nimport { orderedLayers } from '../lib/join.js';\nimport {\n defaultLayerSlider,\n featuresForYear,\n featuresInSliderRange,\n type LayerSlider,\n} from '../lib/legend.js';\nimport {\n choroplethPmtilesSource,\n pmtilesIdExpression,\n toPmtilesFillLayer,\n toPmtilesStrokeLayer,\n type PmtilesLayerConfig,\n} from '../lib/pmtiles.js';\nimport type { ColorRange, GeoJsonFeature, MapHoverEntry, MapLayerModel, MapModel } from '../lib/types.js';\n\nexport type MapMode = 'light' | 'dark';\n\nexport type RenderMapChartOptions = {\n model: MapModel;\n token: string;\n mode?: MapMode;\n showTooltip?: boolean;\n pmtilesBaseUrl?: string;\n activeLayerIds?: string[];\n sliders?: Record<string, LayerSlider>;\n year?: string;\n onHover?: (entry: MapHoverEntry | null) => void;\n};\n\nexport type MapChartController = {\n resize: () => void;\n destroy: () => void;\n setYear: (year: string | undefined) => void;\n applyLegend: (activeLayerIds: string[], sliders: Record<string, LayerSlider>) => void;\n};\n\ntype LiveMapLayer = {\n layerId: string;\n visualisationType: MapVisualisation;\n sourceId: string;\n paintIds: string[];\n fillId?: string;\n yearKey: string;\n features: GeoJsonFeature[];\n colorRanges: ColorRange[];\n pmtilesConfig?: PmtilesLayerConfig;\n};\n\ntype MapboxMap = {\n addSource: (id: string, source: Record<string, unknown>) => void;\n addLayer: (layer: Record<string, unknown>, before?: string) => void;\n addImage: (id: string, image: ImageData, options?: { pixelRatio?: number }) => void;\n getSource: (id: string) => { setData?: (data: unknown) => void } | undefined;\n getLayer: (id: string) => unknown;\n hasImage: (id: string) => boolean;\n removeImage: (id: string) => void;\n setPaintProperty: (id: string, name: string, value: unknown) => void;\n setLayoutProperty: (id: string, name: string, value: unknown) => void;\n setFilter: (id: string, filter: unknown) => void;\n fitBounds: (\n bounds: [[number, number], [number, number]],\n options?: { padding?: number; duration?: number },\n ) => void;\n resize: () => void;\n remove: () => void;\n loaded: () => boolean;\n isStyleLoaded: () => boolean;\n on: (event: string, layerOrHandler: unknown, handler?: unknown) => void;\n off: (event: string, layerOrHandler: unknown, handler?: unknown) => void;\n once: (event: string, handler: () => void) => void;\n queryRenderedFeatures: (\n point: unknown,\n options?: { layers?: string[] },\n ) => Array<{ properties?: Record<string, unknown>; geometry?: { coordinates?: unknown } }>;\n};\n\ntype MapboxModule = {\n default: {\n accessToken: string;\n Map: new (options: Record<string, unknown>) => MapboxMap;\n };\n};\n\nconst controllers = new WeakMap<HTMLElement, MapChartController>();\n\nexport function stopMapChart(container: HTMLElement): void {\n controllers.get(container)?.destroy();\n controllers.delete(container);\n}\n\nexport function resizeMapChart(container: HTMLElement): boolean {\n const ctl = controllers.get(container);\n if (!ctl) return false;\n ctl.resize();\n return true;\n}\n\nexport async function renderMapChart(\n container: HTMLElement,\n options: RenderMapChartOptions,\n): Promise<MapChartController | null> {\n stopMapChart(container);\n container.replaceChildren();\n injectCss(container);\n\n if (!options.token) return null;\n\n let mapbox: MapboxModule;\n try {\n mapbox = (await import('mapbox-gl')) as unknown as MapboxModule;\n } catch {\n return null;\n }\n\n const root = document.createElement('div');\n root.setAttribute('part', 'map');\n root.style.cssText = 'width:100%;height:100%;min-height:inherit;';\n container.append(root);\n\n mapbox.default.accessToken = options.token;\n const map = new mapbox.default.Map({\n container: root,\n style: options.model.terrain\n ? MAP_STYLES.terrain\n : options.mode === 'dark'\n ? MAP_STYLES.dark\n : MAP_STYLES.light,\n center: [0, 20],\n zoom: 1.4,\n attributionControl: true,\n preserveDrawingBuffer: true,\n });\n\n let destroyed = false;\n const layers = orderedLayers(options.model.layers.filter((l) => l.features.length > 0));\n const hover = options.showTooltip === false ? undefined : options.onHover;\n const live: LiveMapLayer[] = [];\n let legend = {\n activeLayerIds: options.activeLayerIds ?? layers.map((layer) => layer.layerId),\n sliders: options.sliders ?? {},\n year: options.year,\n };\n\n const applyLayers = (): void => {\n if (destroyed) return;\n live.length = 0;\n for (const layer of layers) {\n if (layer.visualisationType === 'choropleth') {\n live.push(addChoropleth(map, layer, hover, options.mode, options.pmtilesBaseUrl));\n } else if (layer.visualisationType === 'bubbles') {\n live.push(addCircles(map, layer, 'bubbles', hover));\n } else if (layer.visualisationType === 'markers') {\n live.push(addCircles(map, layer, 'markers', hover));\n } else {\n live.push(addSpikes(map, layer, hover));\n }\n }\n applyLegendState(map, live, legend.activeLayerIds, legend.sliders, legend.year);\n fit(map, layers);\n };\n\n map.once('load', applyLayers);\n if (map.isStyleLoaded() && map.loaded()) applyLayers();\n\n const controller: MapChartController = {\n resize: () => {\n try {\n map.resize();\n } catch {\n /* map already gone */\n }\n },\n destroy: () => {\n destroyed = true;\n try {\n map.remove();\n } catch {\n /* ignore */\n }\n container.replaceChildren();\n },\n setYear: (year) => {\n legend = { ...legend, year };\n if (destroyed) return;\n try {\n if (!map.isStyleLoaded()) return;\n applyLegendState(map, live, legend.activeLayerIds, legend.sliders, legend.year);\n } catch {\n /* style not ready */\n }\n },\n applyLegend: (activeLayerIds, sliders) => {\n legend = { ...legend, activeLayerIds, sliders };\n if (destroyed) return;\n try {\n if (!map.isStyleLoaded()) return;\n applyLegendState(map, live, activeLayerIds, sliders, legend.year);\n } catch {\n /* style not ready */\n }\n },\n };\n controllers.set(container, controller);\n return controller;\n}\n\nfunction injectCss(container: HTMLElement): void {\n const root = container.getRootNode();\n const host = root instanceof ShadowRoot ? root : document.head;\n if (host.querySelector('#ui9000-mapbox-css')) return;\n const link = document.createElement('link');\n link.id = 'ui9000-mapbox-css';\n link.rel = 'stylesheet';\n link.href = MAPBOX_CSS_HREF;\n host.append(link);\n}\n\nfunction addChoropleth(\n map: MapboxMap,\n layer: MapLayerModel,\n onHover: RenderMapChartOptions['onHover'],\n mode?: MapMode,\n pmtilesBaseUrl?: string,\n): LiveMapLayer {\n const queryKey = sanitizeKey(layer.layerId);\n const sourceId = `${layer.mapType}-${queryKey}`;\n const fillId = `${sourceId}-fill-layer`;\n const strokeId = `${sourceId}-selected-stroke-layer`;\n const fillColor = choroplethFillColor(layer, mode);\n const inRangeIds = Object.keys(layer.colorById);\n const pmtiles = choroplethPmtilesSource(layer.mapType, layer.features, pmtilesBaseUrl);\n\n const fillSpec: Record<string, unknown> = {\n id: fillId,\n type: 'fill',\n source: sourceId,\n paint: {\n 'fill-color': fillColor,\n 'fill-opacity': 1,\n },\n };\n const strokeSpec: Record<string, unknown> = {\n id: strokeId,\n type: 'line',\n source: sourceId,\n paint: {\n 'line-color': '#000000',\n 'line-width': 0,\n 'line-opacity': 0,\n },\n };\n\n if (pmtiles) {\n if (!map.getSource(sourceId)) {\n map.addSource(sourceId, {\n type: 'vector',\n provider: 'pmtiles',\n url: pmtiles.url,\n });\n }\n addLayerMaybeBefore(\n map,\n toPmtilesFillLayer(fillSpec, pmtiles.config, inRangeIds),\n );\n if (!map.getLayer(strokeId)) {\n map.addLayer(toPmtilesStrokeLayer(strokeSpec, pmtiles.config));\n }\n const idExpr = pmtilesIdExpression(pmtiles.config);\n bindHover(map, fillId, layer, onHover, (id) => {\n map.setPaintProperty(strokeId, 'line-width', ['case', ['==', idExpr, id ?? ''], 2, 0]);\n map.setPaintProperty(strokeId, 'line-opacity', ['case', ['==', idExpr, id ?? ''], 1, 0]);\n });\n return {\n layerId: layer.layerId,\n visualisationType: 'choropleth',\n sourceId,\n paintIds: [fillId, strokeId],\n fillId,\n yearKey: layer.yearKey,\n features: layer.features,\n colorRanges: layer.colorRanges,\n pmtilesConfig: pmtiles.config,\n };\n }\n\n const collection = {\n type: 'FeatureCollection',\n features: layer.features,\n };\n if (!map.getSource(sourceId)) {\n map.addSource(sourceId, { type: 'geojson', data: collection });\n } else {\n map.getSource(sourceId)?.setData?.(collection);\n }\n\n addLayerMaybeBefore(map, fillSpec);\n if (!map.getLayer(strokeId)) {\n map.addLayer(strokeSpec);\n }\n\n bindHover(map, fillId, layer, onHover, (id) => {\n map.setPaintProperty(strokeId, 'line-width', ['case', ['==', ['get', 'id'], id ?? ''], 2, 0]);\n map.setPaintProperty(strokeId, 'line-opacity', ['case', ['==', ['get', 'id'], id ?? ''], 1, 0]);\n });\n return {\n layerId: layer.layerId,\n visualisationType: 'choropleth',\n sourceId,\n paintIds: [fillId, strokeId],\n fillId,\n yearKey: layer.yearKey,\n features: layer.features,\n colorRanges: layer.colorRanges,\n };\n}\n\nfunction choroplethFillColor(layer: MapLayerModel, mode?: MapMode): unknown {\n const fillColor: unknown[] = ['match', ['get', 'id']];\n for (const [id, color] of Object.entries(layer.colorById)) {\n fillColor.push(id, mode === 'dark' ? hexToRgba(darkenColor(rgbaToHex(color), 0.3), 1) : color);\n }\n fillColor.push(UNMATCHED_FILL);\n return fillColor.length > 3 ? fillColor : UNMATCHED_FILL;\n}\n\nfunction addLayerMaybeBefore(map: MapboxMap, layer: Record<string, unknown>): void {\n if (map.getLayer(String(layer.id))) return;\n try {\n map.addLayer(layer, 'road');\n } catch {\n map.addLayer(layer);\n }\n}\n\nfunction addCircles(\n map: MapboxMap,\n layer: MapLayerModel,\n kind: 'bubbles' | 'markers',\n onHover: RenderMapChartOptions['onHover'],\n): LiveMapLayer {\n const queryKey = sanitizeKey(layer.layerId);\n const sourceId = kind === 'bubbles' ? `bubbles-${queryKey}` : `scatterplot-${queryKey}`;\n const layerId = kind === 'bubbles' ? `bubble-layer-${queryKey}` : `scatterplot-layer-${queryKey}`;\n const collection = { type: 'FeatureCollection', features: layer.features };\n\n if (!map.getSource(sourceId)) {\n map.addSource(sourceId, { type: 'geojson', data: collection });\n } else {\n map.getSource(sourceId)?.setData?.(collection);\n }\n\n const radius =\n kind === 'markers'\n ? 4\n : bubbleRadiusExpression(layer);\n\n if (!map.getLayer(layerId)) {\n map.addLayer({\n id: layerId,\n type: 'circle',\n source: sourceId,\n paint: {\n 'circle-radius': radius,\n 'circle-color': layer.fillColor,\n 'circle-opacity': kind === 'bubbles' ? 0.6 : 0.8,\n 'circle-stroke-width': 1,\n 'circle-stroke-color': kind === 'markers' ? '#fff' : layer.fillColor,\n },\n });\n }\n\n bindHover(map, layerId, layer, onHover);\n return {\n layerId: layer.layerId,\n visualisationType: kind,\n sourceId,\n paintIds: [layerId],\n yearKey: layer.yearKey,\n features: layer.features,\n colorRanges: layer.colorRanges,\n };\n}\n\nfunction addSpikes(\n map: MapboxMap,\n layer: MapLayerModel,\n onHover: RenderMapChartOptions['onHover'],\n): LiveMapLayer {\n const queryKey = sanitizeKey(layer.layerId);\n const sourceId = `spikes-${queryKey}`;\n const layerId = `svg-spikes-layer-${queryKey}`;\n const collection = { type: 'FeatureCollection', features: layer.features };\n\n for (const feature of layer.features) {\n const iconName = feature.properties?.iconName;\n const svg = feature.properties?.svgContent;\n if (typeof iconName !== 'string' || typeof svg !== 'string') continue;\n void loadSpikeIcon(map, iconName, svg);\n }\n\n if (!map.getSource(sourceId)) {\n map.addSource(sourceId, { type: 'geojson', data: collection });\n } else {\n map.getSource(sourceId)?.setData?.(collection);\n }\n\n if (!map.getLayer(layerId)) {\n map.addLayer({\n id: layerId,\n type: 'symbol',\n source: sourceId,\n layout: {\n visibility: 'visible',\n 'icon-image': ['get', 'iconName'],\n 'icon-size': 0.9,\n 'icon-allow-overlap': true,\n 'icon-ignore-placement': true,\n 'icon-anchor': 'bottom',\n },\n paint: { 'icon-opacity': 1 },\n });\n }\n\n bindHover(map, layerId, layer, onHover);\n return {\n layerId: layer.layerId,\n visualisationType: 'spike',\n sourceId,\n paintIds: [layerId],\n yearKey: layer.yearKey,\n features: layer.features,\n colorRanges: layer.colorRanges,\n };\n}\n\nfunction applyLegendState(\n map: MapboxMap,\n live: LiveMapLayer[],\n activeLayerIds: string[],\n sliders: Record<string, LayerSlider>,\n year?: string,\n): void {\n const active = new Set(activeLayerIds);\n for (const layer of live) {\n const visible = active.has(layer.layerId);\n for (const paintId of layer.paintIds) {\n if (!map.getLayer(paintId)) continue;\n try {\n map.setLayoutProperty(paintId, 'visibility', visible ? 'visible' : 'none');\n } catch {\n /* layer not ready */\n }\n }\n if (!visible) continue;\n const slider = sliders[layer.layerId] ?? defaultLayerSlider(layer.colorRanges.length);\n const inYear = featuresForYear(layer.features, year, layer.yearKey);\n const filtered = featuresInSliderRange(inYear, layer.colorRanges, slider);\n if (layer.visualisationType === 'choropleth' && layer.pmtilesConfig && layer.fillId) {\n const ids = [\n ...new Set(\n filtered\n .map((feature) => feature.properties?.id)\n .filter((id): id is string => typeof id === 'string' && id.length > 0),\n ),\n ];\n const filter =\n ids.length > 0\n ? ['in', pmtilesIdExpression(layer.pmtilesConfig), ['literal', ids]]\n : ['==', 1, 0];\n try {\n map.setFilter(layer.fillId, filter);\n } catch {\n /* ignore */\n }\n continue;\n }\n try {\n map.getSource(layer.sourceId)?.setData?.({ type: 'FeatureCollection', features: filtered });\n } catch {\n /* source gone */\n }\n }\n}\n\nfunction bubbleRadiusExpression(layer: MapLayerModel): unknown {\n const ranges = [...layer.colorRanges].sort((a, b) => a.start - b.start);\n if (!ranges.length) return BUBBLE_RADIUS_STEPS[0];\n const expr: unknown[] = [\n 'step',\n ['coalesce', ['to-number', ['get', 'value']], ranges[0].start],\n BUBBLE_RADIUS_STEPS[0],\n ];\n for (let i = 1; i < Math.min(ranges.length, BUBBLE_RADIUS_STEPS.length); i++) {\n expr.push(ranges[i].start, BUBBLE_RADIUS_STEPS[i]);\n }\n return expr.length < 4 ? BUBBLE_RADIUS_STEPS[0] : expr;\n}\n\nfunction bindHover(\n map: MapboxMap,\n layerId: string,\n layer: MapLayerModel,\n onHover: RenderMapChartOptions['onHover'],\n onId?: (id: string | null) => void,\n): void {\n if (!onHover) return;\n\n const read = (properties: Record<string, unknown> | undefined): MapHoverEntry | null => {\n if (!properties) return null;\n const regionId = String(\n getRegionIdFromFeatureProperties(properties, layer.mapType) ??\n properties.id ??\n properties.regionId ??\n '',\n );\n if (!regionId) return null;\n const feature = layer.features.find(\n (f) => String(f.properties?.id ?? f.properties?.regionId) === regionId,\n );\n const props = feature?.properties ?? properties;\n const value = Number(props.value ?? 0);\n const regionName = String(props.regionName ?? props.name ?? regionId);\n return {\n regionId,\n regionName,\n value,\n valueKey: layer.valueKey,\n layerName: layer.layerName,\n lngLat: { lng: 0, lat: 0 },\n };\n };\n\n map.on(\n 'mousemove',\n layerId,\n (e: {\n point?: { x: number; y: number };\n lngLat?: { lng: number; lat: number };\n }) => {\n const feature = map.queryRenderedFeatures(e.point, { layers: [layerId] })[0];\n const entry = read(feature?.properties);\n if (!entry) {\n onId?.(null);\n onHover(null);\n return;\n }\n if (e.lngLat) entry.lngLat = e.lngLat;\n if (e.point) entry.point = e.point;\n onId?.(entry.regionId);\n onHover(entry);\n },\n );\n map.on('mouseleave', layerId, () => {\n onId?.(null);\n onHover(null);\n });\n}\n\nfunction fit(map: MapboxMap, layers: MapLayerModel[]): void {\n const features = layers.flatMap((l) => l.features);\n const box = collectionBBox(features);\n if (!box) return;\n try {\n map.fitBounds(\n [\n [box[0], box[1]],\n [box[2], box[3]],\n ],\n { padding: 64, duration: 750 },\n );\n } catch {\n /* empty bounds */\n }\n}\n\nfunction loadSpikeIcon(map: MapboxMap, iconName: string, svgContent: string): void {\n const svgDataUrl = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgContent)}`;\n const img = new Image();\n img.onload = () => {\n const canvas = document.createElement('canvas');\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n const pixelRatio = 2;\n canvas.width = (img.width || 30) * pixelRatio;\n canvas.height = (img.height || 30) * pixelRatio;\n ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);\n ctx.drawImage(img, 0, 0, img.width || 30, img.height || 30);\n const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);\n if (map.hasImage(iconName)) {\n try {\n map.removeImage(iconName);\n } catch {\n /* ignore */\n }\n }\n try {\n map.addImage(iconName, imageData, { pixelRatio: 2 });\n } catch {\n /* already exists */\n }\n };\n img.src = svgDataUrl;\n}\n\nfunction rgbaToHex(color: string): string {\n const match = color.match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)/);\n if (!match) return color.startsWith('#') ? color : '#473DD9';\n const hex = (n: string) => Number(n).toString(16).padStart(2, '0');\n return `#${hex(match[1])}${hex(match[2])}${hex(match[3])}`;\n}\n"],"names":["_a"],"mappings":"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"}
1
+ {"version":3,"file":"draw.js","sources":["../../../../src/components/map-chart/render/draw.ts"],"sourcesContent":["import {\n BUBBLE_RADIUS_STEPS,\n MAP_STYLES,\n MAPBOX_CSS_HREF,\n UNMATCHED_FILL,\n sanitizeKey,\n type MapVisualisation,\n} from '../lib/constants.js';\nimport { collectionBBox } from '../lib/domain.js';\nimport { darkenColor, hexToRgba } from '../lib/format.js';\nimport { getRegionIdFromFeatureProperties } from '../lib/geo-index.js';\nimport { orderedLayers } from '../lib/join.js';\nimport {\n defaultLayerSlider,\n featuresForYear,\n featuresInSliderRange,\n type LayerSlider,\n} from '../lib/legend.js';\nimport {\n choroplethPmtilesSource,\n pmtilesIdExpression,\n toPmtilesFillLayer,\n toPmtilesStrokeLayer,\n type PmtilesLayerConfig,\n} from '../lib/pmtiles.js';\nimport type { ColorRange, GeoJsonFeature, MapHoverEntry, MapLayerModel, MapModel } from '../lib/types.js';\n\nexport type MapMode = 'light' | 'dark';\n\nexport type RenderMapChartOptions = {\n model: MapModel;\n token: string;\n mode?: MapMode;\n showTooltip?: boolean;\n pmtilesBaseUrl?: string;\n activeLayerIds?: string[];\n sliders?: Record<string, LayerSlider>;\n year?: string;\n onHover?: (entry: MapHoverEntry | null) => void;\n};\n\nexport type MapChartController = {\n resize: () => void;\n destroy: () => void;\n setYear: (year: string | undefined) => void;\n applyLegend: (activeLayerIds: string[], sliders: Record<string, LayerSlider>) => void;\n};\n\ntype LiveMapLayer = {\n layerId: string;\n visualisationType: MapVisualisation;\n sourceId: string;\n paintIds: string[];\n fillId?: string;\n yearKey: string;\n features: GeoJsonFeature[];\n colorRanges: ColorRange[];\n pmtilesConfig?: PmtilesLayerConfig;\n};\n\ntype MapboxMap = {\n addSource: (id: string, source: Record<string, unknown>) => void;\n addLayer: (layer: Record<string, unknown>, before?: string) => void;\n addImage: (id: string, image: ImageData, options?: { pixelRatio?: number }) => void;\n getSource: (id: string) => { setData?: (data: unknown) => void } | undefined;\n getLayer: (id: string) => unknown;\n hasImage: (id: string) => boolean;\n removeImage: (id: string) => void;\n setPaintProperty: (id: string, name: string, value: unknown) => void;\n setLayoutProperty: (id: string, name: string, value: unknown) => void;\n setFilter: (id: string, filter: unknown) => void;\n fitBounds: (\n bounds: [[number, number], [number, number]],\n options?: { padding?: number; duration?: number },\n ) => void;\n resize: () => void;\n remove: () => void;\n loaded: () => boolean;\n isStyleLoaded: () => boolean;\n on: (event: string, layerOrHandler: unknown, handler?: unknown) => void;\n off: (event: string, layerOrHandler: unknown, handler?: unknown) => void;\n once: (event: string, handler: () => void) => void;\n queryRenderedFeatures: (\n point: unknown,\n options?: { layers?: string[] },\n ) => Array<{ properties?: Record<string, unknown>; geometry?: { coordinates?: unknown } }>;\n};\n\ntype MapboxModule = {\n default: {\n accessToken: string;\n Map: new (options: Record<string, unknown>) => MapboxMap;\n };\n};\n\nconst controllers = new WeakMap<HTMLElement, MapChartController>();\n\nexport function stopMapChart(container: HTMLElement): void {\n controllers.get(container)?.destroy();\n controllers.delete(container);\n}\n\nexport function resizeMapChart(container: HTMLElement): boolean {\n const ctl = controllers.get(container);\n if (!ctl) return false;\n ctl.resize();\n return true;\n}\n\nexport async function renderMapChart(\n container: HTMLElement,\n options: RenderMapChartOptions,\n): Promise<MapChartController | null> {\n stopMapChart(container);\n container.replaceChildren();\n injectCss(container);\n\n if (!options.token) return null;\n\n let mapbox: MapboxModule;\n try {\n const runtime = (globalThis as unknown as { mapboxgl?: MapboxModule['default'] }).mapboxgl;\n mapbox = runtime\n ? ({ default: runtime } as MapboxModule)\n : ((await import('mapbox-gl')) as unknown as MapboxModule);\n } catch {\n return null;\n }\n\n const root = document.createElement('div');\n root.setAttribute('part', 'map');\n root.style.cssText = 'width:100%;height:100%;min-height:inherit;';\n container.append(root);\n\n mapbox.default.accessToken = options.token;\n const map = new mapbox.default.Map({\n container: root,\n style: options.model.terrain\n ? MAP_STYLES.terrain\n : options.mode === 'dark'\n ? MAP_STYLES.dark\n : MAP_STYLES.light,\n center: [0, 20],\n zoom: 1.4,\n attributionControl: true,\n preserveDrawingBuffer: true,\n });\n\n let destroyed = false;\n const layers = orderedLayers(options.model.layers.filter((l) => l.features.length > 0));\n const hover = options.showTooltip === false ? undefined : options.onHover;\n const live: LiveMapLayer[] = [];\n let legend = {\n activeLayerIds: options.activeLayerIds ?? layers.map((layer) => layer.layerId),\n sliders: options.sliders ?? {},\n year: options.year,\n };\n\n const applyLayers = (): void => {\n if (destroyed) return;\n live.length = 0;\n for (const layer of layers) {\n if (layer.visualisationType === 'choropleth') {\n live.push(addChoropleth(map, layer, hover, options.mode, options.pmtilesBaseUrl));\n } else if (layer.visualisationType === 'bubbles') {\n live.push(addCircles(map, layer, 'bubbles', hover));\n } else if (layer.visualisationType === 'markers') {\n live.push(addCircles(map, layer, 'markers', hover));\n } else {\n live.push(addSpikes(map, layer, hover));\n }\n }\n applyLegendState(map, live, legend.activeLayerIds, legend.sliders, legend.year);\n fit(map, layers);\n };\n\n map.once('load', applyLayers);\n if (map.isStyleLoaded() && map.loaded()) applyLayers();\n\n const controller: MapChartController = {\n resize: () => {\n try {\n map.resize();\n } catch {\n /* map already gone */\n }\n },\n destroy: () => {\n destroyed = true;\n try {\n map.remove();\n } catch {\n /* ignore */\n }\n container.replaceChildren();\n },\n setYear: (year) => {\n legend = { ...legend, year };\n if (destroyed) return;\n try {\n if (!map.isStyleLoaded()) return;\n applyLegendState(map, live, legend.activeLayerIds, legend.sliders, legend.year);\n } catch {\n /* style not ready */\n }\n },\n applyLegend: (activeLayerIds, sliders) => {\n legend = { ...legend, activeLayerIds, sliders };\n if (destroyed) return;\n try {\n if (!map.isStyleLoaded()) return;\n applyLegendState(map, live, activeLayerIds, sliders, legend.year);\n } catch {\n /* style not ready */\n }\n },\n };\n controllers.set(container, controller);\n return controller;\n}\n\nfunction injectCss(container: HTMLElement): void {\n const root = container.getRootNode();\n const host = root instanceof ShadowRoot ? root : document.head;\n if (host.querySelector('#ui9000-mapbox-css')) return;\n const link = document.createElement('link');\n link.id = 'ui9000-mapbox-css';\n link.rel = 'stylesheet';\n link.href = MAPBOX_CSS_HREF;\n host.append(link);\n}\n\nfunction addChoropleth(\n map: MapboxMap,\n layer: MapLayerModel,\n onHover: RenderMapChartOptions['onHover'],\n mode?: MapMode,\n pmtilesBaseUrl?: string,\n): LiveMapLayer {\n const queryKey = sanitizeKey(layer.layerId);\n const sourceId = `${layer.mapType}-${queryKey}`;\n const fillId = `${sourceId}-fill-layer`;\n const strokeId = `${sourceId}-selected-stroke-layer`;\n const fillColor = choroplethFillColor(layer, mode);\n const inRangeIds = Object.keys(layer.colorById);\n const pmtiles = choroplethPmtilesSource(layer.mapType, layer.features, pmtilesBaseUrl);\n\n const fillSpec: Record<string, unknown> = {\n id: fillId,\n type: 'fill',\n source: sourceId,\n paint: {\n 'fill-color': fillColor,\n 'fill-opacity': 1,\n },\n };\n const strokeSpec: Record<string, unknown> = {\n id: strokeId,\n type: 'line',\n source: sourceId,\n paint: {\n 'line-color': '#000000',\n 'line-width': 0,\n 'line-opacity': 0,\n },\n };\n\n if (pmtiles) {\n if (!map.getSource(sourceId)) {\n map.addSource(sourceId, {\n type: 'vector',\n provider: 'pmtiles',\n url: pmtiles.url,\n });\n }\n addLayerMaybeBefore(\n map,\n toPmtilesFillLayer(fillSpec, pmtiles.config, inRangeIds),\n );\n if (!map.getLayer(strokeId)) {\n map.addLayer(toPmtilesStrokeLayer(strokeSpec, pmtiles.config));\n }\n const idExpr = pmtilesIdExpression(pmtiles.config);\n bindHover(map, fillId, layer, onHover, (id) => {\n map.setPaintProperty(strokeId, 'line-width', ['case', ['==', idExpr, id ?? ''], 2, 0]);\n map.setPaintProperty(strokeId, 'line-opacity', ['case', ['==', idExpr, id ?? ''], 1, 0]);\n });\n return {\n layerId: layer.layerId,\n visualisationType: 'choropleth',\n sourceId,\n paintIds: [fillId, strokeId],\n fillId,\n yearKey: layer.yearKey,\n features: layer.features,\n colorRanges: layer.colorRanges,\n pmtilesConfig: pmtiles.config,\n };\n }\n\n const collection = {\n type: 'FeatureCollection',\n features: layer.features,\n };\n if (!map.getSource(sourceId)) {\n map.addSource(sourceId, { type: 'geojson', data: collection });\n } else {\n map.getSource(sourceId)?.setData?.(collection);\n }\n\n addLayerMaybeBefore(map, fillSpec);\n if (!map.getLayer(strokeId)) {\n map.addLayer(strokeSpec);\n }\n\n bindHover(map, fillId, layer, onHover, (id) => {\n map.setPaintProperty(strokeId, 'line-width', ['case', ['==', ['get', 'id'], id ?? ''], 2, 0]);\n map.setPaintProperty(strokeId, 'line-opacity', ['case', ['==', ['get', 'id'], id ?? ''], 1, 0]);\n });\n return {\n layerId: layer.layerId,\n visualisationType: 'choropleth',\n sourceId,\n paintIds: [fillId, strokeId],\n fillId,\n yearKey: layer.yearKey,\n features: layer.features,\n colorRanges: layer.colorRanges,\n };\n}\n\nfunction choroplethFillColor(layer: MapLayerModel, mode?: MapMode): unknown {\n const fillColor: unknown[] = ['match', ['get', 'id']];\n for (const [id, color] of Object.entries(layer.colorById)) {\n fillColor.push(id, mode === 'dark' ? hexToRgba(darkenColor(rgbaToHex(color), 0.3), 1) : color);\n }\n fillColor.push(UNMATCHED_FILL);\n return fillColor.length > 3 ? fillColor : UNMATCHED_FILL;\n}\n\nfunction addLayerMaybeBefore(map: MapboxMap, layer: Record<string, unknown>): void {\n if (map.getLayer(String(layer.id))) return;\n try {\n map.addLayer(layer, 'road');\n } catch {\n map.addLayer(layer);\n }\n}\n\nfunction addCircles(\n map: MapboxMap,\n layer: MapLayerModel,\n kind: 'bubbles' | 'markers',\n onHover: RenderMapChartOptions['onHover'],\n): LiveMapLayer {\n const queryKey = sanitizeKey(layer.layerId);\n const sourceId = kind === 'bubbles' ? `bubbles-${queryKey}` : `scatterplot-${queryKey}`;\n const layerId = kind === 'bubbles' ? `bubble-layer-${queryKey}` : `scatterplot-layer-${queryKey}`;\n const collection = { type: 'FeatureCollection', features: layer.features };\n\n if (!map.getSource(sourceId)) {\n map.addSource(sourceId, { type: 'geojson', data: collection });\n } else {\n map.getSource(sourceId)?.setData?.(collection);\n }\n\n const radius =\n kind === 'markers'\n ? 4\n : bubbleRadiusExpression(layer);\n\n if (!map.getLayer(layerId)) {\n map.addLayer({\n id: layerId,\n type: 'circle',\n source: sourceId,\n paint: {\n 'circle-radius': radius,\n 'circle-color': layer.fillColor,\n 'circle-opacity': kind === 'bubbles' ? 0.6 : 0.8,\n 'circle-stroke-width': 1,\n 'circle-stroke-color': kind === 'markers' ? '#fff' : layer.fillColor,\n },\n });\n }\n\n bindHover(map, layerId, layer, onHover);\n return {\n layerId: layer.layerId,\n visualisationType: kind,\n sourceId,\n paintIds: [layerId],\n yearKey: layer.yearKey,\n features: layer.features,\n colorRanges: layer.colorRanges,\n };\n}\n\nfunction addSpikes(\n map: MapboxMap,\n layer: MapLayerModel,\n onHover: RenderMapChartOptions['onHover'],\n): LiveMapLayer {\n const queryKey = sanitizeKey(layer.layerId);\n const sourceId = `spikes-${queryKey}`;\n const layerId = `svg-spikes-layer-${queryKey}`;\n const collection = { type: 'FeatureCollection', features: layer.features };\n\n for (const feature of layer.features) {\n const iconName = feature.properties?.iconName;\n const svg = feature.properties?.svgContent;\n if (typeof iconName !== 'string' || typeof svg !== 'string') continue;\n void loadSpikeIcon(map, iconName, svg);\n }\n\n if (!map.getSource(sourceId)) {\n map.addSource(sourceId, { type: 'geojson', data: collection });\n } else {\n map.getSource(sourceId)?.setData?.(collection);\n }\n\n if (!map.getLayer(layerId)) {\n map.addLayer({\n id: layerId,\n type: 'symbol',\n source: sourceId,\n layout: {\n visibility: 'visible',\n 'icon-image': ['get', 'iconName'],\n 'icon-size': 0.9,\n 'icon-allow-overlap': true,\n 'icon-ignore-placement': true,\n 'icon-anchor': 'bottom',\n },\n paint: { 'icon-opacity': 1 },\n });\n }\n\n bindHover(map, layerId, layer, onHover);\n return {\n layerId: layer.layerId,\n visualisationType: 'spike',\n sourceId,\n paintIds: [layerId],\n yearKey: layer.yearKey,\n features: layer.features,\n colorRanges: layer.colorRanges,\n };\n}\n\nfunction applyLegendState(\n map: MapboxMap,\n live: LiveMapLayer[],\n activeLayerIds: string[],\n sliders: Record<string, LayerSlider>,\n year?: string,\n): void {\n const active = new Set(activeLayerIds);\n for (const layer of live) {\n const visible = active.has(layer.layerId);\n for (const paintId of layer.paintIds) {\n if (!map.getLayer(paintId)) continue;\n try {\n map.setLayoutProperty(paintId, 'visibility', visible ? 'visible' : 'none');\n } catch {\n /* layer not ready */\n }\n }\n if (!visible) continue;\n const slider = sliders[layer.layerId] ?? defaultLayerSlider(layer.colorRanges.length);\n const inYear = featuresForYear(layer.features, year, layer.yearKey);\n const filtered = featuresInSliderRange(inYear, layer.colorRanges, slider);\n if (layer.visualisationType === 'choropleth' && layer.pmtilesConfig && layer.fillId) {\n const ids = [\n ...new Set(\n filtered\n .map((feature) => feature.properties?.id)\n .filter((id): id is string => typeof id === 'string' && id.length > 0),\n ),\n ];\n const filter =\n ids.length > 0\n ? ['in', pmtilesIdExpression(layer.pmtilesConfig), ['literal', ids]]\n : ['==', 1, 0];\n try {\n map.setFilter(layer.fillId, filter);\n } catch {\n /* ignore */\n }\n continue;\n }\n try {\n map.getSource(layer.sourceId)?.setData?.({ type: 'FeatureCollection', features: filtered });\n } catch {\n /* source gone */\n }\n }\n}\n\nfunction bubbleRadiusExpression(layer: MapLayerModel): unknown {\n const ranges = [...layer.colorRanges].sort((a, b) => a.start - b.start);\n if (!ranges.length) return BUBBLE_RADIUS_STEPS[0];\n const expr: unknown[] = [\n 'step',\n ['coalesce', ['to-number', ['get', 'value']], ranges[0].start],\n BUBBLE_RADIUS_STEPS[0],\n ];\n for (let i = 1; i < Math.min(ranges.length, BUBBLE_RADIUS_STEPS.length); i++) {\n expr.push(ranges[i].start, BUBBLE_RADIUS_STEPS[i]);\n }\n return expr.length < 4 ? BUBBLE_RADIUS_STEPS[0] : expr;\n}\n\nfunction bindHover(\n map: MapboxMap,\n layerId: string,\n layer: MapLayerModel,\n onHover: RenderMapChartOptions['onHover'],\n onId?: (id: string | null) => void,\n): void {\n if (!onHover) return;\n\n const read = (properties: Record<string, unknown> | undefined): MapHoverEntry | null => {\n if (!properties) return null;\n const regionId = String(\n getRegionIdFromFeatureProperties(properties, layer.mapType) ??\n properties.id ??\n properties.regionId ??\n '',\n );\n if (!regionId) return null;\n const feature = layer.features.find(\n (f) => String(f.properties?.id ?? f.properties?.regionId) === regionId,\n );\n const props = feature?.properties ?? properties;\n const value = Number(props.value ?? 0);\n const regionName = String(props.regionName ?? props.name ?? regionId);\n return {\n regionId,\n regionName,\n value,\n valueKey: layer.valueKey,\n layerName: layer.layerName,\n lngLat: { lng: 0, lat: 0 },\n };\n };\n\n map.on(\n 'mousemove',\n layerId,\n (e: {\n point?: { x: number; y: number };\n lngLat?: { lng: number; lat: number };\n }) => {\n const feature = map.queryRenderedFeatures(e.point, { layers: [layerId] })[0];\n const entry = read(feature?.properties);\n if (!entry) {\n onId?.(null);\n onHover(null);\n return;\n }\n if (e.lngLat) entry.lngLat = e.lngLat;\n if (e.point) entry.point = e.point;\n onId?.(entry.regionId);\n onHover(entry);\n },\n );\n map.on('mouseleave', layerId, () => {\n onId?.(null);\n onHover(null);\n });\n}\n\nfunction fit(map: MapboxMap, layers: MapLayerModel[]): void {\n const features = layers.flatMap((l) => l.features);\n const box = collectionBBox(features);\n if (!box) return;\n try {\n map.fitBounds(\n [\n [box[0], box[1]],\n [box[2], box[3]],\n ],\n { padding: 64, duration: 750 },\n );\n } catch {\n /* empty bounds */\n }\n}\n\nfunction loadSpikeIcon(map: MapboxMap, iconName: string, svgContent: string): void {\n const svgDataUrl = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgContent)}`;\n const img = new Image();\n img.onload = () => {\n const canvas = document.createElement('canvas');\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n const pixelRatio = 2;\n canvas.width = (img.width || 30) * pixelRatio;\n canvas.height = (img.height || 30) * pixelRatio;\n ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);\n ctx.drawImage(img, 0, 0, img.width || 30, img.height || 30);\n const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);\n if (map.hasImage(iconName)) {\n try {\n map.removeImage(iconName);\n } catch {\n /* ignore */\n }\n }\n try {\n map.addImage(iconName, imageData, { pixelRatio: 2 });\n } catch {\n /* already exists */\n }\n };\n img.src = svgDataUrl;\n}\n\nfunction rgbaToHex(color: string): string {\n const match = color.match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)/);\n if (!match) return color.startsWith('#') ? color : '#473DD9';\n const hex = (n: string) => Number(n).toString(16).padStart(2, '0');\n return `#${hex(match[1])}${hex(match[2])}${hex(match[3])}`;\n}\n"],"names":["_a"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const partialDependenceStyles: import('lit').CSSResult;
2
+ //# sourceMappingURL=styles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../../../src/components/partial-dependence-chart/element/styles.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,uBAAuB,yBA0CnC,CAAC"}
@@ -0,0 +1,48 @@
1
+ import { css } from "lit";
2
+ const partialDependenceStyles = css`
3
+ :host {
4
+ display: block;
5
+ position: relative;
6
+ width: 100%;
7
+ height: 100%;
8
+ min-height: 220px;
9
+ color: var(--ui9000-color-text, #111827);
10
+ font-family: var(--ui9000-font-family, system-ui, sans-serif);
11
+ box-sizing: border-box;
12
+ }
13
+ .chart-root {
14
+ flex: 1;
15
+ min-height: 0;
16
+ width: 100%;
17
+ height: 100%;
18
+ min-height: inherit;
19
+ }
20
+ .tooltip {
21
+ position: absolute;
22
+ pointer-events: none;
23
+ z-index: 2;
24
+ padding: 6px 10px;
25
+ border-radius: 6px;
26
+ font-size: 12px;
27
+ line-height: 1.35;
28
+ background: var(--ui9000-color-text, #111827);
29
+ color: #fff;
30
+ box-shadow: 0 4px 12px rgb(0 0 0 / 18%);
31
+ transform: translate(-50%, calc(-100% - 10px));
32
+ white-space: nowrap;
33
+ }
34
+ .empty {
35
+ display: grid;
36
+ place-items: center;
37
+ height: 100%;
38
+ min-height: inherit;
39
+ color: var(--ui9000-color-text-muted, #6b7280);
40
+ font-size: 0.875rem;
41
+ text-align: center;
42
+ padding: 8px;
43
+ }
44
+ `;
45
+ export {
46
+ partialDependenceStyles
47
+ };
48
+ //# sourceMappingURL=styles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styles.js","sources":["../../../../src/components/partial-dependence-chart/element/styles.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const partialDependenceStyles = css`\n :host {\n display: block;\n position: relative;\n width: 100%;\n height: 100%;\n min-height: 220px;\n color: var(--ui9000-color-text, #111827);\n font-family: var(--ui9000-font-family, system-ui, sans-serif);\n box-sizing: border-box;\n }\n .chart-root {\n flex: 1;\n min-height: 0;\n width: 100%;\n height: 100%;\n min-height: inherit;\n }\n .tooltip {\n position: absolute;\n pointer-events: none;\n z-index: 2;\n padding: 6px 10px;\n border-radius: 6px;\n font-size: 12px;\n line-height: 1.35;\n background: var(--ui9000-color-text, #111827);\n color: #fff;\n box-shadow: 0 4px 12px rgb(0 0 0 / 18%);\n transform: translate(-50%, calc(-100% - 10px));\n white-space: nowrap;\n }\n .empty {\n display: grid;\n place-items: center;\n height: 100%;\n min-height: inherit;\n color: var(--ui9000-color-text-muted, #6b7280);\n font-size: 0.875rem;\n text-align: center;\n padding: 8px;\n }\n`;\n"],"names":[],"mappings":";AAEO,MAAM,0BAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;"}