@sproutsocial/seeds-react-data-viz 0.24.3 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/dist/bar/index.js +12 -13
  2. package/dist/bar/index.js.map +1 -1
  3. package/dist/bubble/index.d.mts +1 -1
  4. package/dist/bubble/index.d.ts +1 -1
  5. package/dist/bubble/index.js +9 -10
  6. package/dist/bubble/index.js.map +1 -1
  7. package/dist/{chartOptions-DHzoGRdG.d.mts → chartOptions-D6MzNjbB.d.mts} +3 -1
  8. package/dist/{chartOptions-DHzoGRdG.d.ts → chartOptions-D6MzNjbB.d.ts} +3 -1
  9. package/dist/charts.css +80 -0
  10. package/dist/{chunk-LKUL4EFZ.js → chunk-2A3KLUIF.js} +3 -3
  11. package/dist/{chunk-LKUL4EFZ.js.map → chunk-2A3KLUIF.js.map} +1 -1
  12. package/dist/{chunk-GHZHRFE6.js → chunk-CWKFNAXF.js} +3 -3
  13. package/dist/{chunk-GHZHRFE6.js.map → chunk-CWKFNAXF.js.map} +1 -1
  14. package/dist/{chunk-W57R2V23.js → chunk-LWDHU4QK.js} +183 -7
  15. package/dist/chunk-LWDHU4QK.js.map +1 -0
  16. package/dist/{chunk-5JQXDK23.js → chunk-TNZNBMSZ.js} +292 -73
  17. package/dist/chunk-TNZNBMSZ.js.map +1 -0
  18. package/dist/donut/index.js +6 -7
  19. package/dist/donut/index.js.map +1 -1
  20. package/dist/esm/bar/index.js +6 -7
  21. package/dist/esm/bar/index.js.map +1 -1
  22. package/dist/esm/bubble/index.js +6 -7
  23. package/dist/esm/bubble/index.js.map +1 -1
  24. package/dist/esm/{chunk-AUU3KROF.js → chunk-AJGRGRI6.js} +2 -2
  25. package/dist/esm/{chunk-DF5PVRXT.js → chunk-CIG5NERD.js} +2 -2
  26. package/dist/esm/{chunk-EWAD675C.js → chunk-V63L6753.js} +257 -38
  27. package/dist/esm/chunk-V63L6753.js.map +1 -0
  28. package/dist/esm/{chunk-32QLJDP2.js → chunk-VCTZWYEM.js} +177 -1
  29. package/dist/esm/chunk-VCTZWYEM.js.map +1 -0
  30. package/dist/esm/donut/index.js +4 -5
  31. package/dist/esm/donut/index.js.map +1 -1
  32. package/dist/esm/index.js +15 -15
  33. package/dist/esm/index.js.map +1 -1
  34. package/dist/esm/line-area/index.js +6 -7
  35. package/dist/esm/line-area/index.js.map +1 -1
  36. package/dist/esm/sparkline/index.js +3 -3
  37. package/dist/esm/wordcloud/index.js +82 -0
  38. package/dist/esm/wordcloud/index.js.map +1 -0
  39. package/dist/index.d.mts +1 -1
  40. package/dist/index.d.ts +1 -1
  41. package/dist/index.js +54 -54
  42. package/dist/index.js.map +1 -1
  43. package/dist/line-area/index.js +12 -13
  44. package/dist/line-area/index.js.map +1 -1
  45. package/dist/sparkline/index.js +7 -7
  46. package/dist/wordcloud/index.d.mts +62 -0
  47. package/dist/wordcloud/index.d.ts +62 -0
  48. package/dist/wordcloud/index.js +82 -0
  49. package/dist/wordcloud/index.js.map +1 -0
  50. package/dist/wordcloud.css +79 -0
  51. package/package.json +19 -12
  52. package/dist/chunk-33Y5FZTT.js +0 -177
  53. package/dist/chunk-33Y5FZTT.js.map +0 -1
  54. package/dist/chunk-5JQXDK23.js.map +0 -1
  55. package/dist/chunk-W57R2V23.js.map +0 -1
  56. package/dist/esm/chunk-32QLJDP2.js.map +0 -1
  57. package/dist/esm/chunk-EWAD675C.js.map +0 -1
  58. package/dist/esm/chunk-XRZJACCB.js +0 -177
  59. package/dist/esm/chunk-XRZJACCB.js.map +0 -1
  60. /package/dist/esm/{chunk-AUU3KROF.js.map → chunk-AJGRGRI6.js.map} +0 -0
  61. /package/dist/esm/{chunk-DF5PVRXT.js.map → chunk-CIG5NERD.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/charts/bubble/BubbleChart.tsx","../../../src/charts/bubble/iconMarkup.ts","../../../src/charts/bubble/adapter.ts"],"sourcesContent":["import { memo, useMemo } from \"react\";\nimport {\n ChartRenderer,\n useSeedsChartSetup,\n type ChartTooltipProps,\n} from \"../shared/chartBase\";\nimport { getChartContainerProps } from \"../shared/chartContainer\";\nimport { buildBubbleChartOptions, mapBubbleTooltipRow } from \"./adapter\";\nimport type { BubbleChartProps } from \"./types\";\n\n/**\n * BubbleChart renders a Highcharts packedbubble (clustered, axis-less) chart\n * from a list of categories, each with its own nested inner bubbles.\n *\n * Like DonutChart, it carries no `styled-components`: the wrapper is a plain\n * `<div>` and the Highcharts styling ships as static CSS. Consumers import\n * both `@sproutsocial/seeds-react-data-viz/chart-styles.css` and\n * `.../bubble.css` once (the component never self-imports its CSS).\n */\nexport const BubbleChart = memo(function BubbleChart(props: BubbleChartProps) {\n const { colors } = useSeedsChartSetup({\n series: props.data.map((d) => ({ color: d.color })),\n });\n\n const options = useMemo(() => buildBubbleChartOptions(props), [props]);\n const hasOnClick = Boolean(props.onClick);\n const hasOnPlotBackgroundClick = Boolean(props.onPlotBackgroundClick);\n\n // RAW per-category colors only — an unset category falls through to\n // chart-styles.css's --highcharts-color-N default, matching the bar\n // convention (bubble's outer categories are separate series, like bar's,\n // not donut's single-series-many-points model).\n const containerProps = getChartContainerProps({\n familyClasses: [\"seeds-chart-bubble\"],\n colors: props.data.map((d) => d.color),\n hasOnClick,\n className: props.className,\n });\n\n // `ChartRenderer` expects `(ChartTooltipProps) => ReactNode`; the consumer's\n // function expects the narrower `BubbleChartTooltipProps` (required\n // seriesIndex/pointIndex). Wrap rather than cast the function type so the\n // intent is explicit; `mapBubbleTooltipRow` applies the remount-desync null\n // guard.\n const tooltip = props.tooltip\n ? (args: ChartTooltipProps) => {\n const row = mapBubbleTooltipRow(args.data);\n if (!row) return null;\n return props.tooltip!({ ...args, data: [row] });\n }\n : undefined;\n\n return (\n <div\n {...containerProps}\n {...(hasOnPlotBackgroundClick\n ? { \"data-has-on-plot-background-click\": \"\" }\n : {})}\n onClick={props.onPlotBackgroundClick}\n >\n <ChartRenderer\n // Highcharts <12.2.0 can't re-run the packedbubble split layout when\n // `splitSeries` toggles (highcharts/highcharts#21972, fixed by #22186\n // in 12.2.0), so we force a full remount via `key`. REMOVE this `key`\n // once seeds is on Highcharts >=12.2.0.\n // Unrelated, but a watch-item for that same upgrade: the #21972 fix\n // (#22186) introduced a still-open regression, #24134, where 2+\n // packedbubble charts that are BOTH in split mode at the same time on\n // one page share a global `allParentNodes` array, causing one chart's\n // bubbles to drift outside its plot area. A single bubble chart (or\n // several where at most one is split) is unaffected — only\n // simultaneous multi-chart split mode triggers it. Doesn't affect this\n // usage today (Smart Categories renders one bubble chart at a time),\n // but if a future surface ever renders 2+ split bubble charts at\n // once post-upgrade, apply the maintainers' workaround (reset\n // `allParentNodes` on chart `init`) until Highcharts ships a fix.\n key={`Bubble-Chart-${props.splitSeries ? \"SplitSeries\" : \"\"}`}\n options={options}\n series={props.data.map((d, i) => ({\n name: d.name,\n color: d.color ?? colors[i],\n }))}\n colors={colors}\n tooltip={tooltip}\n hasOnClick={hasOnClick}\n tooltipClickLabel={props.tooltipClickLabel}\n invalidNumberLabel={props.invalidNumberLabel}\n valueFormat={props.format}\n hideLegend\n exportTitle={props.exportTitle}\n onReady={props.onReady}\n />\n </div>\n );\n});\n","/**\n * TEMPORARY — remove when CE-202 lands (this file and its import in\n * `adapter.ts`).\n *\n * Raw inline-SVG markup for the bubble chart's data-label icons, duplicated\n * verbatim from web-app-core v1's `smartCategoryToSVGMap`\n * (`SmartCategoriesBubbleChart.tsx`), re-keyed from entity type to the Seeds\n * icon name the chart's `icon` prop actually receives (the Listening consumer\n * maps entity type -> icon name via `EntityTypeIconMap`). Copying v1's exact\n * glyphs is what guarantees pixel parity with the live chart.\n *\n * WHY inline SVG rather than the Seeds sprite `<use xlink:href=\"#seeds-svgs_...\">`:\n * Highcharts renders `useHTML` data labels outside the light-DOM tree the\n * sprite sheet is injected into, so cross-tree `<use>` resolution fails. This\n * is the same wall v1 hit, which is why it hand-copied raw path data instead\n * of referencing the sprite. The general fix — a lightweight per-icon markup\n * export from seeds-icons that avoids pulling the whole ~300KB+/category\n * sprite bundle into every `seeds-react-data-viz` consumer — is tracked by\n * CE-202; when it lands, resolve icons through that and delete this file.\n *\n * Fills are `currentColor` so each glyph inherits the data-label text color.\n * Each SVG keeps its native `width`/`height` for v1-identical inline sizing.\n * An icon outside this map degrades to the no-icon (name-only) label rather\n * than rendering nothing.\n */\nexport const BUBBLE_ICON_MARKUP: Record<string, string> = {\n \"user-outline\": `<svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M5.72756 6C7.38441 6 8.72756 4.65685 8.72756 3C8.72756 1.34315 7.38441 0 5.72756 0C4.07071 0 2.72756 1.34315 2.72756 3C2.72756 4.65685 4.07071 6 5.72756 6Z\" fill=\"currentColor\"/>\n<path d=\"M5.72756 12C8.50201 12 10.1833 10.1963 11.0339 8.89858C11.4669 8.23803 11.0644 7.41859 10.2861 7.28445C8.63561 7 7.15327 7 5.72756 7C4.30185 7 2.81951 7 1.16899 7.28445C0.390671 7.41859 -0.0117778 8.23803 0.421187 8.89858C1.2718 10.1963 2.95311 12 5.72756 12Z\" fill=\"currentColor\"/>\n</svg>`,\n \"location-pin-outline\": `<svg width=\"10\" height=\"12\" viewBox=\"0 0 10 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path style=\"fill-rule: evenodd; clip-rule: evenodd;\" d=\"M4.99992 12C6.33325 12 9.66659 7.244 9.66659 4.66667C9.66659 2.08934 7.57725 0 4.99992 0C2.42259 0 0.333252 2.08934 0.333252 4.66667C0.333252 7.244 3.66659 12 4.99992 12ZM4.99992 4.66667C5.36811 4.66667 5.66659 4.36819 5.66659 4C5.66659 3.63181 5.36811 3.33333 4.99992 3.33333C4.63173 3.33333 4.33325 3.63181 4.33325 4C4.33325 4.36819 4.63173 4.66667 4.99992 4.66667Z\" fill=\"currentColor\"/>\n</svg>`,\n \"cart-outline\": `<svg width=\"11\" height=\"12\" viewBox=\"0 0 11 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M0.666748 1.83333H1.76749C1.93793 1.83333 2.08092 1.96192 2.09895 2.1314L2.75892 8.33515C1.9651 8.37397 1.33341 9.02988 1.33341 9.83333C1.33341 10.6618 2.00499 11.3333 2.83341 11.3333C3.66184 11.3333 4.33341 10.6618 4.33341 9.83333C4.33341 9.777 4.33031 9.72139 4.32426 9.66667H7.34257C7.33652 9.72139 7.33341 9.777 7.33341 9.83333C7.33341 10.6618 8.00499 11.3333 8.83341 11.3333C9.66184 11.3333 10.3334 10.6618 10.3334 9.83333C10.3334 9.00491 9.66184 8.33333 8.83341 8.33333H4.09959L3.92228 6.66667H9.18028C9.65696 6.66667 10.0674 6.33021 10.1609 5.86278L10.9203 2.06537C10.9616 1.85911 10.8038 1.66667 10.5935 1.66667H3.35763C3.14364 0.98448 2.50729 0.5 1.76749 0.5H0.666748V1.83333Z\" fill=\"currentColor\"/>\n</svg>`,\n \"briefcase-outline\": `<svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path style=\"fill-rule: evenodd; clip-rule: evenodd;\" d=\"M3.5 1.83333V2H1C0.447715 2 0 2.44772 0 3V10.3333C0 10.8856 0.447715 11.3333 1 11.3333H11C11.5523 11.3333 12 10.8856 12 10.3333V3C12 2.44772 11.5523 2 11 2H8.5V1.83333C8.5 0.820811 7.67919 0 6.66667 0H5.33333C4.32081 0 3.5 0.820811 3.5 1.83333ZM5.33333 1C4.8731 1 4.5 1.3731 4.5 1.83333V2H7.5V1.83333C7.5 1.3731 7.1269 1 6.66667 1H5.33333ZM6.66667 5.33333C6.66667 5.70152 6.36819 6 6 6C5.63181 6 5.33333 5.70152 5.33333 5.33333C5.33333 4.96514 5.63181 4.66667 6 4.66667C6.36819 4.66667 6.66667 4.96514 6.66667 5.33333ZM10.6667 6.88767V5.74479C9.44176 6.48334 7.81474 6.95116 6 6.95116C4.18526 6.95116 2.55823 6.48334 1.33333 5.74479V6.88767C2.64682 7.55696 4.25842 7.95116 6 7.95116C7.74158 7.95116 9.35318 7.55696 10.6667 6.88767Z\" fill=\"currentColor\"/>\n</svg>`,\n \"laptop-mobile-outline\": `<svg width=\"13\" height=\"10\" viewBox=\"0 0 13 10\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M2.84994 0.333313C2.29765 0.333313 1.84993 0.781028 1.84993 1.33331V7.33331H0.516602C0.516602 7.8856 0.964317 8.33331 1.5166 8.33331H6.84994V3.33331C6.84994 2.22874 7.74537 1.33331 8.84994 1.33331H11.1833C11.1833 0.781028 10.7356 0.333313 10.1833 0.333313H2.84994Z\" fill=\"currentColor\"/>\n<path style=\"fill-rule: evenodd; clip-rule: evenodd;\" d=\"M7.84994 3.33331C7.84994 2.78103 8.29765 2.33331 8.84994 2.33331H11.5166C12.0689 2.33331 12.5166 2.78103 12.5166 3.33331V8.66665C12.5166 9.21893 12.0689 9.66665 11.5166 9.66665H8.84994C8.29765 9.66665 7.84994 9.21893 7.84994 8.66665V3.33331ZM10.6833 8.16665C10.6833 8.44279 10.4594 8.66665 10.1833 8.66665C9.90713 8.66665 9.68327 8.44279 9.68327 8.16665C9.68327 7.8905 9.90713 7.66665 10.1833 7.66665C10.4594 7.66665 10.6833 7.8905 10.6833 8.16665Z\" fill=\"currentColor\"/>\n</svg>`,\n \"calendar-day-outline\": `<svg width=\"11\" height=\"12\" viewBox=\"0 0 11 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path style=\"fill-rule: evenodd; clip-rule: evenodd;\" d=\"M3.3632 1.33333H7.69653V0H8.69653V1.33333H9.8632C10.4155 1.33333 10.8632 1.78105 10.8632 2.33333V10.3333C10.8632 10.8856 10.4155 11.3333 9.8632 11.3333H1.19653C0.644248 11.3333 0.196533 10.8856 0.196533 10.3333V2.33333C0.196533 1.78105 0.644248 1.33333 1.19653 1.33333H2.3632V0H3.3632V1.33333ZM1.52987 2.66667V4H9.52987V2.66667H1.52987ZM3.8632 5.33333H1.8632V7.33333H3.8632V5.33333Z\" fill=\"currentColor\"/>\n</svg>`,\n \"chart-pie-outline\": `<svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path style=\"fill-rule: evenodd; clip-rule: evenodd;\" d=\"M10.9888 9.33342C11.6481 8.34673 12 7.18669 12 6H6V0C4.81331 0 3.65328 0.351894 2.66658 1.01118C1.67989 1.67047 0.910851 2.60754 0.456725 3.7039C0.00259971 4.80026 -0.11622 6.00666 0.115291 7.17054C0.346802 8.33443 0.918247 9.40353 1.75736 10.2426C2.59648 11.0818 3.66557 11.6532 4.82946 11.8847C5.99335 12.1162 7.19975 11.9974 8.2961 11.5433C9.39246 11.0892 10.3295 10.3201 10.9888 9.33342ZM7.33334 4.66672L11.8513 4.66656C11.3422 2.42346 9.57645 0.657717 7.33334 0.148727V4.66672Z\" fill=\"currentColor\"/>\n</svg>`,\n \"paper-outline\": `<svg width=\"10\" height=\"12\" viewBox=\"0 0 10 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M1.06836 12C0.516075 12 0.0683594 11.5523 0.0683594 11V1C0.0683594 0.447715 0.516075 0 1.06836 0H3.73503C4.28731 0 4.73503 0.447715 4.73503 1V2.83333C4.73503 4.02995 5.70508 5 6.90169 5H8.40169C8.95398 5 9.40169 5.44772 9.40169 6V11C9.40169 11.5523 8.95398 12 8.40169 12H1.06836Z\" fill=\"currentColor\"/>\n<path d=\"M5.73503 2.49999V0.107381C7.61938 0.518781 9.07818 2.06865 9.35443 3.99999H7.23503C6.4066 3.99999 5.73503 3.32841 5.73503 2.49999Z\" fill=\"currentColor\"/>\n</svg>`,\n};\n","import type { TypeIconName } from \"@sproutsocial/seeds-react-icon\";\nimport { BUBBLE_ICON_MARKUP } from \"./iconMarkup\";\nimport { buildBaseChartOptions } from \"../shared/baseChartOptions\";\nimport type {\n ChartTooltipDataRow,\n SeedsChartBubbleClickEvent,\n SeedsChartBubbleDataLabelFormatterContext,\n SeedsChartOptions,\n SeedsChartPackedBubbleSeriesOptions,\n} from \"../shared/chartBase\";\nimport {\n BUBBLE_CHART_DEFAULT_MAX_SIZE,\n BUBBLE_CHART_DEFAULT_PADDING,\n BUBBLE_CHART_HEIGHT,\n} from \"../../constants/chartOptions\";\nimport type {\n BubbleCategoryDataPoint,\n BubbleChartClickData,\n BubbleChartProps,\n BubbleChartTooltipRow,\n} from \"./types\";\n\nfunction defaultPointDescriptionFormatter(point: {\n name: string;\n value: number;\n}): string {\n return `${point.name}: ${point.value}. Press Enter or Space to activate.`;\n}\n\n/**\n * A bare icon name (no `-outline`/`-solid` suffix) resolves to its default\n * variant, matching `seeds-react-icon`'s own `resolveIconName` (`outline` at\n * this label's rendered size — mirrors non-mini `<Icon>` sizing, since\n * `BUBBLE_ICON_MARKUP` only stocks the outline variant).\n */\nfunction resolveIconName(name: TypeIconName): string {\n return name.endsWith(\"-outline\") || name.endsWith(\"-solid\")\n ? name\n : `${name}-outline`;\n}\n\n// Icon markup lives in ./iconMarkup (a verbatim, temporary duplicate of v1's\n// raw-SVG map — see that file's header and CE-202). Kept out of this adapter so\n// the eventual general fix is a one-file deletion, not a surgical edit here.\nfunction buildIconMarkup(icon: TypeIconName): string | undefined {\n return BUBBLE_ICON_MARKUP[resolveIconName(icon)];\n}\n\nfunction escapeHtml(value: string): string {\n return value\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\");\n}\n\n// v1's radius thresholds (`MINIMUM_BUBBLE_RADIUS_FOR_CATEGORY_TEXT` /\n// `MINIMUM_BUBBLE_RADIUS_FOR_DATALABEL_TEXT`), generalized per SPEC decision\n// 9a: the rule is icon-presence-driven, not view-mode-driven. v1 conflated the\n// two because overview-mode categories were the only points it ever assigned\n// an icon to — incidental, not load-bearing.\nconst ICON_LABEL_TEXT_MIN_RADIUS = 40;\nconst NO_ICON_LABEL_MIN_RADIUS = 25;\n\n/**\n * Assembles a packedbubble data label as an HTML string (`useHTML: true`,\n * required — see `charts/README.md`'s known gap, mirrored from v1). Icon\n * present → icon always renders, name conditional on radius; no icon → hidden\n * below a radius floor, else the name clipped/wrapped to the bubble's\n * diameter. Mirrors v1's `dataLabelFormatter` exactly: a plain `<div>` with the\n * inline icon to the left of the name (v1 does nothing more — it relies on the\n * browser-default inline `<svg>`; see bubble.css for the Tailwind-Preflight\n * override that keeps that default intact here). An `icon` outside\n * `BUBBLE_ICON_MARKUP`'s current coverage falls through to the no-icon branch\n * (name only) rather than rendering an empty/broken icon.\n */\nfunction buildBubbleDataLabel(\n point: { name: string; icon?: TypeIconName },\n radius: number\n): string {\n const name = escapeHtml(point.name);\n const iconMarkup = point.icon ? buildIconMarkup(point.icon) : undefined;\n if (iconMarkup) {\n const showName = radius > ICON_LABEL_TEXT_MIN_RADIUS;\n return `<div>${iconMarkup}${showName ? ` <span>${name}</span>` : \"\"}</div>`;\n }\n if (radius < NO_ICON_LABEL_MIN_RADIUS) return \"\";\n const diameter = radius * 2;\n return `<div style=\"max-width: ${diameter}px; max-height: ${diameter}px; overflow: hidden; text-overflow: ellipsis; white-space: wrap;\" title=\"${name}\">${name}</div>`;\n}\n\nexport function transformBubbleDataToSeries(\n data: Array<BubbleCategoryDataPoint>\n): Array<SeedsChartPackedBubbleSeriesOptions> {\n return data.map((category, index) => ({\n type: \"packedbubble\",\n name: category.name,\n data: category.innerBubbles.map((bubble) => ({\n name: bubble.name,\n value: bubble.value,\n })),\n color: category.color,\n colorIndex: index,\n }));\n}\n\n/**\n * Keyboard activation has no `stopPropagation` and its `type` isn't `\"click\"`;\n * derive `pageX`/`pageY` from the target's bounding rect for keyboard, from\n * the raw event for a mouse click. Mirrors v1's `transformBubbleChartClickData`.\n */\nexport function transformBubbleClickData(\n event: SeedsChartBubbleClickEvent\n): BubbleChartClickData {\n const base = {\n name: event.point.name,\n value: event.point.value,\n seriesIndex: event.point.series.index,\n pointIndex: event.point.index,\n };\n const isClickEvent = event.type === \"click\";\n if (!isClickEvent && event.target) {\n const rect = (event.target as HTMLElement).getBoundingClientRect();\n return { ...base, pageX: rect.x, pageY: rect.y };\n }\n return { ...base, pageX: event.pageX ?? 0, pageY: event.pageY ?? 0 };\n}\n\n/**\n * During the split<->unsplit remount transition the tooltip context is\n * briefly missing data (name/seriesIndex undefined) — bail rather than render\n * a broken tooltip. Mirrors v1.\n */\nexport function mapBubbleTooltipRow(\n data: ChartTooltipDataRow[]\n): BubbleChartTooltipRow | null {\n const row = data[0] as BubbleChartTooltipRow | undefined;\n if (row?.name == null || row?.seriesIndex == null) return null;\n return row;\n}\n\nexport function buildBubbleChartOptions(\n props: BubbleChartProps\n): SeedsChartOptions {\n const hasOnClick = Boolean(props.onClick);\n const base = buildBaseChartOptions({\n type: \"packedbubble\",\n description: props.accessibility.description,\n svgContainerLabel: props.accessibility.svgContainerLabel,\n ...(hasOnClick\n ? {\n point: {\n descriptionFormatter:\n props.accessibility.point?.descriptionFormatter ??\n defaultPointDescriptionFormatter,\n },\n }\n : {}),\n });\n\n return {\n ...base,\n chart: {\n ...base.chart,\n type: \"packedbubble\",\n height: props.height ?? BUBBLE_CHART_HEIGHT,\n },\n plotOptions: {\n packedbubble: {\n minSize: \"30%\",\n maxSize: props.maxBubbleSize ?? BUBBLE_CHART_DEFAULT_MAX_SIZE,\n draggable: false,\n states: { hover: { enabled: false } },\n layoutAlgorithm: {\n gravitationalConstant: 0.05,\n seriesInteraction: true,\n parentNodeLimit: true,\n enableSimulation: false,\n bubblePadding: props.bubblePadding ?? BUBBLE_CHART_DEFAULT_PADDING,\n splitSeries: props.splitSeries ?? false,\n },\n dataLabels: {\n enabled: true,\n // See chartBase.tsx's SeedsChartPackedBubblePlotOptions.dataLabels —\n // the label formatter returns HTML (icon + wrapped text); preserved\n // for functional parity (known useHTML gap, mirrors bar's axis\n // labels).\n useHTML: true,\n formatter(this: SeedsChartBubbleDataLabelFormatterContext) {\n const inner =\n props.data[this.point.series.index]?.innerBubbles[\n this.point.index\n ];\n return buildBubbleDataLabel(\n { name: this.point.name, icon: inner?.icon },\n this.radius\n );\n },\n },\n accessibility: {\n enabled: true,\n keyboardNavigation: { enabled: true },\n point: { valueDescriptionFormat: \"{point.name}: {point.value}\" },\n },\n point: {\n events: {\n click: hasOnClick\n ? (event: SeedsChartBubbleClickEvent) => {\n event.stopPropagation?.();\n // Keyboard events have no `target` when not a genuine click.\n if (event.type !== \"click\" && !event.target) return;\n props.onClick!(transformBubbleClickData(event));\n }\n : undefined,\n mouseOver: props.onMouseEnter\n ? function (this: { name: string }) {\n props.onMouseEnter!({ position: this.name });\n }\n : undefined,\n mouseOut: props.onMouseLeave\n ? function (this: { name: string }) {\n props.onMouseLeave!({ position: this.name });\n }\n : undefined,\n },\n },\n },\n },\n series: transformBubbleDataToSeries(props.data),\n };\n}\n"],"mappings":"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","names":["BubbleChart"]}
1
+ {"version":3,"sources":["../../../src/charts/bubble/BubbleChart.tsx","../../../src/charts/bubble/iconMarkup.ts","../../../src/charts/bubble/adapter.ts"],"sourcesContent":["import { memo, useMemo } from \"react\";\nimport {\n ChartRenderer,\n useSeedsChartSetup,\n type ChartTooltipProps,\n} from \"../shared/chartBase\";\nimport { getChartContainerProps } from \"../shared/chartContainer\";\nimport { buildBubbleChartOptions, mapBubbleTooltipRow } from \"./adapter\";\nimport type { BubbleChartProps } from \"./types\";\n\n/**\n * BubbleChart renders a Highcharts packedbubble (clustered, axis-less) chart\n * from a list of categories, each with its own nested inner bubbles.\n *\n * Like DonutChart, it carries no `styled-components`: the wrapper is a plain\n * `<div>` and the Highcharts styling ships as static CSS. Consumers import\n * both `@sproutsocial/seeds-react-data-viz/chart-styles.css` and\n * `.../bubble.css` once (the component never self-imports its CSS).\n */\nexport const BubbleChart = memo(function BubbleChart(props: BubbleChartProps) {\n const { colors } = useSeedsChartSetup({\n series: props.data.map((d) => ({ color: d.color })),\n });\n\n const options = useMemo(() => buildBubbleChartOptions(props), [props]);\n const hasOnClick = Boolean(props.onClick);\n const hasOnPlotBackgroundClick = Boolean(props.onPlotBackgroundClick);\n\n // RAW per-category colors only — an unset category falls through to\n // chart-styles.css's --highcharts-color-N default, matching the bar\n // convention (bubble's outer categories are separate series, like bar's,\n // not donut's single-series-many-points model).\n const containerProps = getChartContainerProps({\n familyClasses: [\"seeds-chart-bubble\"],\n colors: props.data.map((d) => d.color),\n hasOnClick,\n className: props.className,\n });\n\n // `ChartRenderer` expects `(ChartTooltipProps) => ReactNode`; the consumer's\n // function expects the narrower `BubbleChartTooltipProps` (required\n // seriesIndex/pointIndex). Wrap rather than cast the function type so the\n // intent is explicit; `mapBubbleTooltipRow` applies the remount-desync null\n // guard.\n const tooltip = props.tooltip\n ? (args: ChartTooltipProps) => {\n const row = mapBubbleTooltipRow(args.data);\n if (!row) return null;\n return props.tooltip!({ ...args, data: [row] });\n }\n : undefined;\n\n return (\n <div\n {...containerProps}\n {...(hasOnPlotBackgroundClick\n ? { \"data-has-on-plot-background-click\": \"\" }\n : {})}\n onClick={props.onPlotBackgroundClick}\n >\n <ChartRenderer\n // Highcharts <12.2.0 can't re-run the packedbubble split layout when\n // `splitSeries` toggles (highcharts/highcharts#21972, fixed by #22186\n // in 12.2.0), so we force a full remount via `key`. REMOVE this `key`\n // once seeds is on Highcharts >=12.2.0.\n // Unrelated, but a watch-item for that same upgrade: the #21972 fix\n // (#22186) introduced a still-open regression, #24134, where 2+\n // packedbubble charts that are BOTH in split mode at the same time on\n // one page share a global `allParentNodes` array, causing one chart's\n // bubbles to drift outside its plot area. A single bubble chart (or\n // several where at most one is split) is unaffected — only\n // simultaneous multi-chart split mode triggers it. Doesn't affect this\n // usage today (Smart Categories renders one bubble chart at a time),\n // but if a future surface ever renders 2+ split bubble charts at\n // once post-upgrade, apply the maintainers' workaround (reset\n // `allParentNodes` on chart `init`) until Highcharts ships a fix.\n key={`Bubble-Chart-${props.splitSeries ? \"SplitSeries\" : \"\"}`}\n options={options}\n series={props.data.map((d, i) => ({\n name: d.name,\n color: d.color ?? colors[i],\n }))}\n colors={colors}\n tooltip={tooltip}\n hasOnClick={hasOnClick}\n tooltipClickLabel={props.tooltipClickLabel}\n invalidNumberLabel={props.invalidNumberLabel}\n valueFormat={props.format}\n hideLegend\n exportTitle={props.exportTitle}\n onReady={props.onReady}\n />\n </div>\n );\n});\n","/**\n * TEMPORARY — remove when CE-202 lands (this file and its import in\n * `adapter.ts`).\n *\n * Raw inline-SVG markup for the bubble chart's data-label icons, duplicated\n * verbatim from web-app-core v1's `smartCategoryToSVGMap`\n * (`SmartCategoriesBubbleChart.tsx`), re-keyed from entity type to the Seeds\n * icon name the chart's `icon` prop actually receives (the Listening consumer\n * maps entity type -> icon name via `EntityTypeIconMap`). Copying v1's exact\n * glyphs is what guarantees pixel parity with the live chart.\n *\n * WHY inline SVG rather than the Seeds sprite `<use xlink:href=\"#seeds-svgs_...\">`:\n * Highcharts renders `useHTML` data labels outside the light-DOM tree the\n * sprite sheet is injected into, so cross-tree `<use>` resolution fails. This\n * is the same wall v1 hit, which is why it hand-copied raw path data instead\n * of referencing the sprite. The general fix — a lightweight per-icon markup\n * export from seeds-icons that avoids pulling the whole ~300KB+/category\n * sprite bundle into every `seeds-react-data-viz` consumer — is tracked by\n * CE-202; when it lands, resolve icons through that and delete this file.\n *\n * Fills are `currentColor` so each glyph inherits the data-label text color.\n * Each SVG keeps its native `width`/`height` for v1-identical inline sizing.\n * An icon outside this map degrades to the no-icon (name-only) label rather\n * than rendering nothing.\n */\nexport const BUBBLE_ICON_MARKUP: Record<string, string> = {\n \"user-outline\": `<svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M5.72756 6C7.38441 6 8.72756 4.65685 8.72756 3C8.72756 1.34315 7.38441 0 5.72756 0C4.07071 0 2.72756 1.34315 2.72756 3C2.72756 4.65685 4.07071 6 5.72756 6Z\" fill=\"currentColor\"/>\n<path d=\"M5.72756 12C8.50201 12 10.1833 10.1963 11.0339 8.89858C11.4669 8.23803 11.0644 7.41859 10.2861 7.28445C8.63561 7 7.15327 7 5.72756 7C4.30185 7 2.81951 7 1.16899 7.28445C0.390671 7.41859 -0.0117778 8.23803 0.421187 8.89858C1.2718 10.1963 2.95311 12 5.72756 12Z\" fill=\"currentColor\"/>\n</svg>`,\n \"location-pin-outline\": `<svg width=\"10\" height=\"12\" viewBox=\"0 0 10 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path style=\"fill-rule: evenodd; clip-rule: evenodd;\" d=\"M4.99992 12C6.33325 12 9.66659 7.244 9.66659 4.66667C9.66659 2.08934 7.57725 0 4.99992 0C2.42259 0 0.333252 2.08934 0.333252 4.66667C0.333252 7.244 3.66659 12 4.99992 12ZM4.99992 4.66667C5.36811 4.66667 5.66659 4.36819 5.66659 4C5.66659 3.63181 5.36811 3.33333 4.99992 3.33333C4.63173 3.33333 4.33325 3.63181 4.33325 4C4.33325 4.36819 4.63173 4.66667 4.99992 4.66667Z\" fill=\"currentColor\"/>\n</svg>`,\n \"cart-outline\": `<svg width=\"11\" height=\"12\" viewBox=\"0 0 11 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M0.666748 1.83333H1.76749C1.93793 1.83333 2.08092 1.96192 2.09895 2.1314L2.75892 8.33515C1.9651 8.37397 1.33341 9.02988 1.33341 9.83333C1.33341 10.6618 2.00499 11.3333 2.83341 11.3333C3.66184 11.3333 4.33341 10.6618 4.33341 9.83333C4.33341 9.777 4.33031 9.72139 4.32426 9.66667H7.34257C7.33652 9.72139 7.33341 9.777 7.33341 9.83333C7.33341 10.6618 8.00499 11.3333 8.83341 11.3333C9.66184 11.3333 10.3334 10.6618 10.3334 9.83333C10.3334 9.00491 9.66184 8.33333 8.83341 8.33333H4.09959L3.92228 6.66667H9.18028C9.65696 6.66667 10.0674 6.33021 10.1609 5.86278L10.9203 2.06537C10.9616 1.85911 10.8038 1.66667 10.5935 1.66667H3.35763C3.14364 0.98448 2.50729 0.5 1.76749 0.5H0.666748V1.83333Z\" fill=\"currentColor\"/>\n</svg>`,\n \"briefcase-outline\": `<svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path style=\"fill-rule: evenodd; clip-rule: evenodd;\" d=\"M3.5 1.83333V2H1C0.447715 2 0 2.44772 0 3V10.3333C0 10.8856 0.447715 11.3333 1 11.3333H11C11.5523 11.3333 12 10.8856 12 10.3333V3C12 2.44772 11.5523 2 11 2H8.5V1.83333C8.5 0.820811 7.67919 0 6.66667 0H5.33333C4.32081 0 3.5 0.820811 3.5 1.83333ZM5.33333 1C4.8731 1 4.5 1.3731 4.5 1.83333V2H7.5V1.83333C7.5 1.3731 7.1269 1 6.66667 1H5.33333ZM6.66667 5.33333C6.66667 5.70152 6.36819 6 6 6C5.63181 6 5.33333 5.70152 5.33333 5.33333C5.33333 4.96514 5.63181 4.66667 6 4.66667C6.36819 4.66667 6.66667 4.96514 6.66667 5.33333ZM10.6667 6.88767V5.74479C9.44176 6.48334 7.81474 6.95116 6 6.95116C4.18526 6.95116 2.55823 6.48334 1.33333 5.74479V6.88767C2.64682 7.55696 4.25842 7.95116 6 7.95116C7.74158 7.95116 9.35318 7.55696 10.6667 6.88767Z\" fill=\"currentColor\"/>\n</svg>`,\n \"laptop-mobile-outline\": `<svg width=\"13\" height=\"10\" viewBox=\"0 0 13 10\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M2.84994 0.333313C2.29765 0.333313 1.84993 0.781028 1.84993 1.33331V7.33331H0.516602C0.516602 7.8856 0.964317 8.33331 1.5166 8.33331H6.84994V3.33331C6.84994 2.22874 7.74537 1.33331 8.84994 1.33331H11.1833C11.1833 0.781028 10.7356 0.333313 10.1833 0.333313H2.84994Z\" fill=\"currentColor\"/>\n<path style=\"fill-rule: evenodd; clip-rule: evenodd;\" d=\"M7.84994 3.33331C7.84994 2.78103 8.29765 2.33331 8.84994 2.33331H11.5166C12.0689 2.33331 12.5166 2.78103 12.5166 3.33331V8.66665C12.5166 9.21893 12.0689 9.66665 11.5166 9.66665H8.84994C8.29765 9.66665 7.84994 9.21893 7.84994 8.66665V3.33331ZM10.6833 8.16665C10.6833 8.44279 10.4594 8.66665 10.1833 8.66665C9.90713 8.66665 9.68327 8.44279 9.68327 8.16665C9.68327 7.8905 9.90713 7.66665 10.1833 7.66665C10.4594 7.66665 10.6833 7.8905 10.6833 8.16665Z\" fill=\"currentColor\"/>\n</svg>`,\n \"calendar-day-outline\": `<svg width=\"11\" height=\"12\" viewBox=\"0 0 11 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path style=\"fill-rule: evenodd; clip-rule: evenodd;\" d=\"M3.3632 1.33333H7.69653V0H8.69653V1.33333H9.8632C10.4155 1.33333 10.8632 1.78105 10.8632 2.33333V10.3333C10.8632 10.8856 10.4155 11.3333 9.8632 11.3333H1.19653C0.644248 11.3333 0.196533 10.8856 0.196533 10.3333V2.33333C0.196533 1.78105 0.644248 1.33333 1.19653 1.33333H2.3632V0H3.3632V1.33333ZM1.52987 2.66667V4H9.52987V2.66667H1.52987ZM3.8632 5.33333H1.8632V7.33333H3.8632V5.33333Z\" fill=\"currentColor\"/>\n</svg>`,\n \"chart-pie-outline\": `<svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path style=\"fill-rule: evenodd; clip-rule: evenodd;\" d=\"M10.9888 9.33342C11.6481 8.34673 12 7.18669 12 6H6V0C4.81331 0 3.65328 0.351894 2.66658 1.01118C1.67989 1.67047 0.910851 2.60754 0.456725 3.7039C0.00259971 4.80026 -0.11622 6.00666 0.115291 7.17054C0.346802 8.33443 0.918247 9.40353 1.75736 10.2426C2.59648 11.0818 3.66557 11.6532 4.82946 11.8847C5.99335 12.1162 7.19975 11.9974 8.2961 11.5433C9.39246 11.0892 10.3295 10.3201 10.9888 9.33342ZM7.33334 4.66672L11.8513 4.66656C11.3422 2.42346 9.57645 0.657717 7.33334 0.148727V4.66672Z\" fill=\"currentColor\"/>\n</svg>`,\n \"paper-outline\": `<svg width=\"10\" height=\"12\" viewBox=\"0 0 10 12\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M1.06836 12C0.516075 12 0.0683594 11.5523 0.0683594 11V1C0.0683594 0.447715 0.516075 0 1.06836 0H3.73503C4.28731 0 4.73503 0.447715 4.73503 1V2.83333C4.73503 4.02995 5.70508 5 6.90169 5H8.40169C8.95398 5 9.40169 5.44772 9.40169 6V11C9.40169 11.5523 8.95398 12 8.40169 12H1.06836Z\" fill=\"currentColor\"/>\n<path d=\"M5.73503 2.49999V0.107381C7.61938 0.518781 9.07818 2.06865 9.35443 3.99999H7.23503C6.4066 3.99999 5.73503 3.32841 5.73503 2.49999Z\" fill=\"currentColor\"/>\n</svg>`,\n};\n","import type { TypeIconName } from \"@sproutsocial/seeds-react-icon\";\nimport { BUBBLE_ICON_MARKUP } from \"./iconMarkup\";\nimport { buildBaseChartOptions } from \"../shared/baseChartOptions\";\nimport type {\n ChartTooltipDataRow,\n SeedsChartBubbleClickEvent,\n SeedsChartBubbleDataLabelFormatterContext,\n SeedsChartOptions,\n SeedsChartPackedBubbleSeriesOptions,\n} from \"../shared/chartBase\";\nimport {\n BUBBLE_CHART_DEFAULT_MAX_SIZE,\n BUBBLE_CHART_DEFAULT_PADDING,\n BUBBLE_CHART_HEIGHT,\n} from \"../../constants/chartOptions\";\nimport type {\n BubbleCategoryDataPoint,\n BubbleChartClickData,\n BubbleChartProps,\n BubbleChartTooltipRow,\n} from \"./types\";\n\nfunction defaultPointDescriptionFormatter(point: {\n name: string;\n value: number;\n}): string {\n return `${point.name}: ${point.value}. Press Enter or Space to activate.`;\n}\n\n/**\n * A bare icon name (no `-outline`/`-solid` suffix) resolves to its default\n * variant, matching `seeds-react-icon`'s own `resolveIconName` (`outline` at\n * this label's rendered size — mirrors non-mini `<Icon>` sizing, since\n * `BUBBLE_ICON_MARKUP` only stocks the outline variant).\n */\nfunction resolveIconName(name: TypeIconName): string {\n return name.endsWith(\"-outline\") || name.endsWith(\"-solid\")\n ? name\n : `${name}-outline`;\n}\n\n// Icon markup lives in ./iconMarkup (a verbatim, temporary duplicate of v1's\n// raw-SVG map — see that file's header and CE-202). Kept out of this adapter so\n// the eventual general fix is a one-file deletion, not a surgical edit here.\nfunction buildIconMarkup(icon: TypeIconName): string | undefined {\n return BUBBLE_ICON_MARKUP[resolveIconName(icon)];\n}\n\nfunction escapeHtml(value: string): string {\n return value\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\");\n}\n\n// v1's radius thresholds (`MINIMUM_BUBBLE_RADIUS_FOR_CATEGORY_TEXT` /\n// `MINIMUM_BUBBLE_RADIUS_FOR_DATALABEL_TEXT`), generalized per SPEC decision\n// 9a: the rule is icon-presence-driven, not view-mode-driven. v1 conflated the\n// two because overview-mode categories were the only points it ever assigned\n// an icon to — incidental, not load-bearing.\nconst ICON_LABEL_TEXT_MIN_RADIUS = 40;\nconst NO_ICON_LABEL_MIN_RADIUS = 25;\n\n/**\n * Assembles a packedbubble data label as an HTML string (`useHTML: true`,\n * required — see `charts/README.md`'s known gap, mirrored from v1). Icon\n * present → icon always renders, name conditional on radius; no icon → hidden\n * below a radius floor, else the name clipped/wrapped to the bubble's\n * diameter. Mirrors v1's `dataLabelFormatter` exactly: a plain `<div>` with the\n * inline icon to the left of the name (v1 does nothing more — it relies on the\n * browser-default inline `<svg>`; see bubble.css for the Tailwind-Preflight\n * override that keeps that default intact here). An `icon` outside\n * `BUBBLE_ICON_MARKUP`'s current coverage falls through to the no-icon branch\n * (name only) rather than rendering an empty/broken icon.\n */\nfunction buildBubbleDataLabel(\n point: { name: string; icon?: TypeIconName },\n radius: number\n): string {\n const name = escapeHtml(point.name);\n const iconMarkup = point.icon ? buildIconMarkup(point.icon) : undefined;\n if (iconMarkup) {\n const showName = radius > ICON_LABEL_TEXT_MIN_RADIUS;\n return `<div>${iconMarkup}${showName ? ` <span>${name}</span>` : \"\"}</div>`;\n }\n if (radius < NO_ICON_LABEL_MIN_RADIUS) return \"\";\n const diameter = radius * 2;\n return `<div style=\"max-width: ${diameter}px; max-height: ${diameter}px; overflow: hidden; text-overflow: ellipsis; white-space: wrap;\" title=\"${name}\">${name}</div>`;\n}\n\nexport function transformBubbleDataToSeries(\n data: Array<BubbleCategoryDataPoint>\n): Array<SeedsChartPackedBubbleSeriesOptions> {\n return data.map((category, index) => ({\n type: \"packedbubble\",\n name: category.name,\n data: category.innerBubbles.map((bubble) => ({\n name: bubble.name,\n value: bubble.value,\n })),\n color: category.color,\n colorIndex: index,\n }));\n}\n\n/**\n * Keyboard activation has no `stopPropagation` and its `type` isn't `\"click\"`;\n * derive `pageX`/`pageY` from the target's bounding rect for keyboard, from\n * the raw event for a mouse click. Mirrors v1's `transformBubbleChartClickData`.\n */\nexport function transformBubbleClickData(\n event: SeedsChartBubbleClickEvent\n): BubbleChartClickData {\n const base = {\n name: event.point.name,\n value: event.point.value,\n seriesIndex: event.point.series.index,\n pointIndex: event.point.index,\n };\n const isClickEvent = event.type === \"click\";\n if (!isClickEvent && event.target) {\n const rect = (event.target as HTMLElement).getBoundingClientRect();\n return { ...base, pageX: rect.x, pageY: rect.y };\n }\n return { ...base, pageX: event.pageX ?? 0, pageY: event.pageY ?? 0 };\n}\n\n/**\n * During the split<->unsplit remount transition the tooltip context is\n * briefly missing data (name/seriesIndex undefined) — bail rather than render\n * a broken tooltip. Mirrors v1.\n */\nexport function mapBubbleTooltipRow(\n data: ChartTooltipDataRow[]\n): BubbleChartTooltipRow | null {\n const row = data[0] as BubbleChartTooltipRow | undefined;\n if (row?.name == null || row?.seriesIndex == null) return null;\n return row;\n}\n\nexport function buildBubbleChartOptions(\n props: BubbleChartProps\n): SeedsChartOptions {\n const hasOnClick = Boolean(props.onClick);\n const base = buildBaseChartOptions({\n type: \"packedbubble\",\n description: props.accessibility.description,\n svgContainerLabel: props.accessibility.svgContainerLabel,\n ...(hasOnClick\n ? {\n point: {\n descriptionFormatter:\n props.accessibility.point?.descriptionFormatter ??\n defaultPointDescriptionFormatter,\n },\n }\n : {}),\n });\n\n return {\n ...base,\n chart: {\n ...base.chart,\n type: \"packedbubble\",\n height: props.height ?? BUBBLE_CHART_HEIGHT,\n },\n plotOptions: {\n packedbubble: {\n minSize: \"30%\",\n maxSize: props.maxBubbleSize ?? BUBBLE_CHART_DEFAULT_MAX_SIZE,\n draggable: false,\n states: { hover: { enabled: false } },\n layoutAlgorithm: {\n gravitationalConstant: 0.05,\n seriesInteraction: true,\n parentNodeLimit: true,\n enableSimulation: false,\n bubblePadding: props.bubblePadding ?? BUBBLE_CHART_DEFAULT_PADDING,\n splitSeries: props.splitSeries ?? false,\n },\n dataLabels: {\n enabled: true,\n // See chartBase.tsx's SeedsChartPackedBubblePlotOptions.dataLabels —\n // the label formatter returns HTML (icon + wrapped text); preserved\n // for functional parity (known useHTML gap, mirrors bar's axis\n // labels).\n useHTML: true,\n formatter(this: SeedsChartBubbleDataLabelFormatterContext) {\n const inner =\n props.data[this.point.series.index]?.innerBubbles[\n this.point.index\n ];\n return buildBubbleDataLabel(\n { name: this.point.name, icon: inner?.icon },\n this.radius\n );\n },\n },\n accessibility: {\n enabled: true,\n keyboardNavigation: { enabled: true },\n point: { valueDescriptionFormat: \"{point.name}: {point.value}\" },\n },\n point: {\n events: {\n click: hasOnClick\n ? (event: SeedsChartBubbleClickEvent) => {\n event.stopPropagation?.();\n // Keyboard events have no `target` when not a genuine click.\n if (event.type !== \"click\" && !event.target) return;\n props.onClick!(transformBubbleClickData(event));\n }\n : undefined,\n mouseOver: props.onMouseEnter\n ? function (this: { name: string }) {\n props.onMouseEnter!({ position: this.name });\n }\n : undefined,\n mouseOut: props.onMouseLeave\n ? function (this: { name: string }) {\n props.onMouseLeave!({ position: this.name });\n }\n : undefined,\n },\n },\n },\n },\n series: transformBubbleDataToSeries(props.data),\n };\n}\n"],"mappings":"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","names":["BubbleChart"]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  valueFormatter
3
- } from "./chunk-EWAD675C.js";
3
+ } from "./chunk-V63L6753.js";
4
4
 
5
5
  // src/charts/shared/annotations.ts
6
6
  function buildAnnotationConfig(annotations) {
@@ -65,4 +65,4 @@ export {
65
65
  defaultValueAxisLabelFormatter,
66
66
  makeValueAxisLabelFormatter
67
67
  };
68
- //# sourceMappingURL=chunk-AUU3KROF.js.map
68
+ //# sourceMappingURL=chunk-AJGRGRI6.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  datetimeFormatter
3
- } from "./chunk-EWAD675C.js";
3
+ } from "./chunk-V63L6753.js";
4
4
 
5
5
  // src/charts/shared/axisOptions.ts
6
6
  function makeDatetimeAxisLabelFormatter(timezone, timeFormat) {
@@ -53,4 +53,4 @@ export {
53
53
  buildDimensionalAxis,
54
54
  resolveTooltipOptions
55
55
  };
56
- //# sourceMappingURL=chunk-DF5PVRXT.js.map
56
+ //# sourceMappingURL=chunk-CIG5NERD.js.map
@@ -8,8 +8,252 @@ import {
8
8
  ChartTooltipTable,
9
9
  ChartTooltipTitle,
10
10
  GlobalChartStyleOverrides,
11
+ WORD_CLOUD_CHART_HEIGHT,
11
12
  transformTimeSeriesTooltipData
12
- } from "./chunk-32QLJDP2.js";
13
+ } from "./chunk-VCTZWYEM.js";
14
+
15
+ // src/charts/shared/baseChartOptions.ts
16
+ function buildBaseChartOptions({
17
+ type,
18
+ description,
19
+ svgContainerLabel,
20
+ point,
21
+ reserveTopMargin = false,
22
+ timezone
23
+ }) {
24
+ return {
25
+ chart: {
26
+ type,
27
+ styledMode: true,
28
+ animation: false,
29
+ ...reserveTopMargin ? { marginTop: 24 } : {}
30
+ },
31
+ accessibility: { description, svgContainerLabel, point },
32
+ title: { text: "" },
33
+ credits: { enabled: false },
34
+ legend: { enabled: false },
35
+ tooltip: {
36
+ enabled: true,
37
+ outside: true,
38
+ padding: 0,
39
+ shape: "rect",
40
+ shared: true,
41
+ hideDelay: 0
42
+ },
43
+ // Chart-global in Highcharts; only meaningful for datetime axes, so it's
44
+ // present only when a timezone was resolved (omitted for category axes).
45
+ ...timezone ? { time: { timezone } } : {}
46
+ };
47
+ }
48
+
49
+ // src/charts/wordcloud/adapter.ts
50
+ var DEFAULT_OPACITY_RANGE = [0.6, 1];
51
+ var WORD_CLOUD_MIN_FONT_SIZE = 13;
52
+ var WORD_CLOUD_MAXIMUM_MAX_FONT_SIZE = 50;
53
+ var WORD_CLOUD_MINIMUM_MAX_FONT_SIZE = 24;
54
+ var WORD_CLOUD_MAX_FONT_SIZE_WIDTH_DIVISOR = 15;
55
+ function deriveMaxFontSize(width) {
56
+ if (!width) return WORD_CLOUD_MAXIMUM_MAX_FONT_SIZE;
57
+ const derived = Math.floor(width / WORD_CLOUD_MAX_FONT_SIZE_WIDTH_DIVISOR);
58
+ return Math.min(
59
+ Math.max(derived, WORD_CLOUD_MINIMUM_MAX_FONT_SIZE),
60
+ WORD_CLOUD_MAXIMUM_MAX_FONT_SIZE
61
+ );
62
+ }
63
+ var WORD_CLOUD_MAXIMUM_WORD_COUNT = 100;
64
+ var WORD_CLOUD_MINIMUM_WORD_COUNT = 40;
65
+ var WORD_CLOUD_WORD_COUNT_WIDTH_DIVISOR = 9;
66
+ function deriveMaxWordCount(width) {
67
+ if (!width) return WORD_CLOUD_MAXIMUM_WORD_COUNT;
68
+ const derived = Math.floor(width / WORD_CLOUD_WORD_COUNT_WIDTH_DIVISOR);
69
+ return Math.min(
70
+ Math.max(derived, WORD_CLOUD_MINIMUM_WORD_COUNT),
71
+ WORD_CLOUD_MAXIMUM_WORD_COUNT
72
+ );
73
+ }
74
+ var WORD_CLOUD_MAXIMUM_WORD_PADDING = 4;
75
+ var WORD_CLOUD_MINIMUM_WORD_PADDING = 1;
76
+ var WORD_CLOUD_WORD_PADDING_WIDTH_DIVISOR = 150;
77
+ function deriveWordPadding(width) {
78
+ if (!width) return WORD_CLOUD_MAXIMUM_WORD_PADDING;
79
+ const derived = Math.floor(width / WORD_CLOUD_WORD_PADDING_WIDTH_DIVISOR);
80
+ return Math.min(
81
+ Math.max(derived, WORD_CLOUD_MINIMUM_WORD_PADDING),
82
+ WORD_CLOUD_MAXIMUM_WORD_PADDING
83
+ );
84
+ }
85
+ var wordCloudAspectArchimedeanSpiral = (attempt, { field }) => {
86
+ const maxDelta = field.width * field.width + field.height * field.height;
87
+ if (attempt > 1e4) return false;
88
+ const t = attempt * 0.8;
89
+ const result = {
90
+ x: field.ratioX * t * Math.cos(t),
91
+ y: field.ratioY * t * Math.sin(t)
92
+ };
93
+ if (!(Math.min(Math.abs(result.x), Math.abs(result.y)) < maxDelta)) {
94
+ return false;
95
+ }
96
+ return result;
97
+ };
98
+ var wordCloudPaddingPlacementStrategy = (point) => {
99
+ const wordPadding = point.series.options.wordPadding ?? 0;
100
+ point.dimensions = {
101
+ width: point.dimensions.width + wordPadding * 2,
102
+ height: point.dimensions.height + wordPadding * 2
103
+ };
104
+ return { x: 0, y: 0, rotation: false };
105
+ };
106
+ var EMOJI_ONLY_TERM_REGEX = /^(?:\p{Extended_Pictographic}|\p{Regional_Indicator}|\u{1F3FB}|\u{1F3FC}|\u{1F3FD}|\u{1F3FE}|\u{1F3FF}|\u200D|\uFE0F)+$/u;
107
+ function isEmojiOnlyTerm(name) {
108
+ return EMOJI_ONLY_TERM_REGEX.test(name);
109
+ }
110
+ function resolveGroupColorIndex(groupId, groups) {
111
+ if (!groups || groups.length === 0 || groupId == null) return 0;
112
+ const index = groups.findIndex((group) => group.id === groupId);
113
+ return index === -1 ? 0 : index;
114
+ }
115
+ function normalizeWeight(weight, min, max) {
116
+ return max === min ? 1 : (weight - min) / (max - min);
117
+ }
118
+ function compressWeight(weight) {
119
+ return Math.log(Math.max(weight, 1));
120
+ }
121
+ function resolvePointOpacity({
122
+ weight,
123
+ min,
124
+ max,
125
+ hasGroups,
126
+ isEmojiOnly,
127
+ opacityRange
128
+ }) {
129
+ if (hasGroups) return 1;
130
+ const [rangeMin, rangeMax] = opacityRange;
131
+ if (isEmojiOnly) return rangeMax;
132
+ const t = normalizeWeight(weight, min, max);
133
+ return rangeMin + t * (rangeMax - rangeMin);
134
+ }
135
+ function transformWordCloudDataToPoints(data, groups, opacityRange, maxWordCount = WORD_CLOUD_MAXIMUM_WORD_COUNT) {
136
+ const capped = [...data].sort((a, b) => b.weight - a.weight).slice(0, maxWordCount);
137
+ const hasGroups = Boolean(groups && groups.length > 0);
138
+ const compressedWeights = capped.map((point) => compressWeight(point.weight));
139
+ const min = Math.min(...compressedWeights);
140
+ const max = Math.max(...compressedWeights);
141
+ return capped.map((point, i) => {
142
+ const colorIndex = resolveGroupColorIndex(point.groupId, groups);
143
+ const weight = compressedWeights[i];
144
+ return {
145
+ name: point.name,
146
+ weight,
147
+ colorIndex,
148
+ opacity: resolvePointOpacity({
149
+ weight,
150
+ min,
151
+ max,
152
+ hasGroups,
153
+ isEmojiOnly: isEmojiOnlyTerm(point.name),
154
+ opacityRange
155
+ }),
156
+ className: `seeds-wordcloud-word--group-${colorIndex}`,
157
+ custom: { groupId: point.groupId, rawWeight: point.weight }
158
+ };
159
+ });
160
+ }
161
+ function transformWordCloudClickData(event) {
162
+ const base = {
163
+ name: event.point.name,
164
+ weight: event.point.custom?.rawWeight ?? event.point.weight,
165
+ groupId: event.point.custom?.groupId,
166
+ pointIndex: event.point.index
167
+ };
168
+ const isClickEvent = event.type === "click";
169
+ if (!isClickEvent && event.target) {
170
+ const rect = event.target.getBoundingClientRect();
171
+ return { ...base, pageX: rect.x, pageY: rect.y };
172
+ }
173
+ return { ...base, pageX: event.pageX ?? 0, pageY: event.pageY ?? 0 };
174
+ }
175
+ function buildWordCloudOptions(props, containerWidth) {
176
+ const opacityRange = props.opacityRange ?? DEFAULT_OPACITY_RANGE;
177
+ const points = transformWordCloudDataToPoints(
178
+ props.data,
179
+ props.groups,
180
+ opacityRange,
181
+ deriveMaxWordCount(containerWidth ?? 0)
182
+ );
183
+ const base = buildBaseChartOptions({
184
+ type: "wordcloud",
185
+ description: props.description
186
+ });
187
+ return {
188
+ ...base,
189
+ chart: {
190
+ ...base.chart,
191
+ type: "wordcloud",
192
+ height: props.height ?? WORD_CLOUD_CHART_HEIGHT
193
+ },
194
+ // `ChartRenderer`'s default-tooltip routing only recognizes "pie" and
195
+ // "packedbubble" as single-point (non-cartesian) series types
196
+ // (chartBase.tsx); an unrecognized type like "wordcloud" falls through to
197
+ // the time-series branch, which reads `context.x` as a timestamp and
198
+ // renders a bogus epoch-date title. Disabled entirely rather than adding
199
+ // a wordcloud branch to shared code — the word's size/opacity already
200
+ // communicates weight.
201
+ tooltip: { ...base.tooltip, enabled: false },
202
+ plotOptions: {
203
+ // `series.animation: false` matches the sibling-adapter convention, but
204
+ // the wordcloud series overrides it back to `true`: Highcharts 11.4.8's
205
+ // WordcloudSeries.drawPoints() only builds `animatableAttribs` inside an
206
+ // `if (animation)` branch (wordcloud.src.js ~line 1243). With animation
207
+ // off, any point that was previously placed but fails to re-place on a
208
+ // later redraw hits `DPU.draw()`'s point-removal path with
209
+ // `animatableAttribs: undefined`, and `Object.keys(undefined)` throws.
210
+ // A component's routine post-mount `chart.update()` triggers exactly
211
+ // this, so it surfaces on a plain mount, not just on resize.
212
+ series: { animation: false },
213
+ wordcloud: {
214
+ animation: true,
215
+ // Hover dim (layer 3). Off by default for column-derived series
216
+ // (wordcloud's base class) — pie is the only series type that
217
+ // defaults this to `true`. Without it, Highcharts never adds
218
+ // `.highcharts-point-inactive` to the other words on hover.
219
+ inactiveOtherPoints: true,
220
+ minFontSize: props.minFontSize ?? WORD_CLOUD_MIN_FONT_SIZE,
221
+ // An explicit prop wins; otherwise derived from the measured
222
+ // container width (`WordCloud.tsx`'s `useMeasure` call). Must stay a
223
+ // number — see `WORD_CLOUD_MAXIMUM_MAX_FONT_SIZE`'s doc comment for
224
+ // why `undefined` breaks sizing.
225
+ maxFontSize: props.maxFontSize ?? deriveMaxFontSize(containerWidth ?? 0),
226
+ // Pinned horizontal — Highcharts' default tilts words vertical
227
+ // (`{from: 0, to: 90}`).
228
+ rotation: { from: 0, to: 0, orientations: 1 },
229
+ // `seedsAspectArchimedean` (a pure function above, registered onto
230
+ // Highcharts in chartBase.tsx) — Highcharts' own `archimedean` traces
231
+ // a true circle with no aspect term, so it can't grow into a wide
232
+ // container.
233
+ spiral: "seedsAspectArchimedean",
234
+ // `seedsWordPadding` (a pure function above, registered onto
235
+ // Highcharts in chartBase.tsx) approximates word spacing, which
236
+ // Highcharts' wordcloud module has no native option for; it reads
237
+ // `wordPadding` off this same resolved options object. An explicit
238
+ // prop wins; otherwise derived from the measured container width
239
+ // (`deriveWordPadding`) — see its doc comment for why a fixed
240
+ // padding disproportionately shrinks text on a narrow container.
241
+ placementStrategy: "seedsWordPadding",
242
+ wordPadding: props.wordPadding ?? deriveWordPadding(containerWidth ?? 0),
243
+ point: {
244
+ events: {
245
+ click: props.onClick ? (event) => {
246
+ event.stopPropagation?.();
247
+ if (event.type !== "click" && !event.target) return;
248
+ props.onClick(transformWordCloudClickData(event));
249
+ } : void 0
250
+ }
251
+ }
252
+ }
253
+ },
254
+ series: points.length > 0 ? [{ type: "wordcloud", name: "Word Cloud", data: points }] : []
255
+ };
256
+ }
13
257
 
14
258
  // src/charts/shared/chartBase.tsx
15
259
  import Highcharts from "highcharts";
@@ -20,6 +264,7 @@ import highchartsExporting from "highcharts/modules/exporting";
20
264
  import highchartsOfflineExporting from "highcharts/modules/offline-exporting";
21
265
  import highchartsExportData from "highcharts/modules/export-data";
22
266
  import highchartsMore from "highcharts/highcharts-more";
267
+ import highchartsWordcloud from "highcharts/modules/wordcloud";
23
268
  import {
24
269
  useCallback,
25
270
  useEffect as useEffect2,
@@ -505,6 +750,10 @@ highchartsExporting(Highcharts);
505
750
  highchartsOfflineExporting(Highcharts);
506
751
  highchartsExportData(Highcharts);
507
752
  highchartsMore(Highcharts);
753
+ highchartsWordcloud(Highcharts);
754
+ var wordcloudSeriesPrototype = Highcharts.seriesTypes.wordcloud.prototype;
755
+ wordcloudSeriesPrototype.spirals.seedsAspectArchimedean = wordCloudAspectArchimedeanSpiral;
756
+ wordcloudSeriesPrototype.placementStrategy.seedsWordPadding = wordCloudPaddingPlacementStrategy;
508
757
  function isChartStacked(options) {
509
758
  const plotOptions = options.plotOptions;
510
759
  if (!plotOptions) return false;
@@ -872,45 +1121,15 @@ function ChartRenderer({
872
1121
  ] });
873
1122
  }
874
1123
 
875
- // src/charts/shared/baseChartOptions.ts
876
- function buildBaseChartOptions({
877
- type,
878
- description,
879
- svgContainerLabel,
880
- point,
881
- reserveTopMargin = false,
882
- timezone
883
- }) {
884
- return {
885
- chart: {
886
- type,
887
- styledMode: true,
888
- animation: false,
889
- ...reserveTopMargin ? { marginTop: 24 } : {}
890
- },
891
- accessibility: { description, svgContainerLabel, point },
892
- title: { text: "" },
893
- credits: { enabled: false },
894
- legend: { enabled: false },
895
- tooltip: {
896
- enabled: true,
897
- outside: true,
898
- padding: 0,
899
- shape: "rect",
900
- shared: true,
901
- hideDelay: 0
902
- },
903
- // Chart-global in Highcharts; only meaningful for datetime axes, so it's
904
- // present only when a timezone was resolved (omitted for category axes).
905
- ...timezone ? { time: { timezone } } : {}
906
- };
907
- }
908
-
909
1124
  export {
910
1125
  datetimeFormatter,
911
1126
  valueFormatter,
1127
+ buildBaseChartOptions,
1128
+ deriveMaxFontSize,
1129
+ deriveMaxWordCount,
1130
+ deriveWordPadding,
1131
+ buildWordCloudOptions,
912
1132
  useSeedsChartSetup,
913
- ChartRenderer,
914
- buildBaseChartOptions
1133
+ ChartRenderer
915
1134
  };
916
- //# sourceMappingURL=chunk-EWAD675C.js.map
1135
+ //# sourceMappingURL=chunk-V63L6753.js.map