@tetrascience-npm/tetrascience-react-ui 1.0.0-beta.147.1 → 1.0.0-beta.149.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.
- package/README.md +65 -7
- package/dist/components/charts/AreaPlot/AreaPlot.cjs +1 -1
- package/dist/components/charts/AreaPlot/AreaPlot.cjs.map +1 -1
- package/dist/components/charts/AreaPlot/AreaPlot.js +166 -148
- package/dist/components/charts/AreaPlot/AreaPlot.js.map +1 -1
- package/dist/components/charts/BarChart/BarChart.cjs +1 -1
- package/dist/components/charts/BarChart/BarChart.cjs.map +1 -1
- package/dist/components/charts/BarChart/BarChart.d.ts +7 -0
- package/dist/components/charts/BarChart/BarChart.js +151 -120
- package/dist/components/charts/BarChart/BarChart.js.map +1 -1
- package/dist/components/charts/BoxPlot/BoxPlot.cjs +1 -1
- package/dist/components/charts/BoxPlot/BoxPlot.cjs.map +1 -1
- package/dist/components/charts/BoxPlot/BoxPlot.d.ts +4 -0
- package/dist/components/charts/BoxPlot/BoxPlot.js +133 -102
- package/dist/components/charts/BoxPlot/BoxPlot.js.map +1 -1
- package/dist/components/charts/ChartTooltip/lines.cjs.map +1 -1
- package/dist/components/charts/ChartTooltip/lines.d.ts +2 -0
- package/dist/components/charts/ChartTooltip/lines.js.map +1 -1
- package/dist/components/charts/Chromatogram/Chromatogram.cjs +1 -1
- package/dist/components/charts/Chromatogram/Chromatogram.cjs.map +1 -1
- package/dist/components/charts/Chromatogram/Chromatogram.js +111 -114
- package/dist/components/charts/Chromatogram/Chromatogram.js.map +1 -1
- package/dist/components/charts/Chromatogram/plotBuilder.cjs +4 -1
- package/dist/components/charts/Chromatogram/plotBuilder.cjs.map +1 -1
- package/dist/components/charts/Chromatogram/plotBuilder.d.ts +32 -2
- package/dist/components/charts/Chromatogram/plotBuilder.js +170 -127
- package/dist/components/charts/Chromatogram/plotBuilder.js.map +1 -1
- package/dist/components/charts/Chromatogram/regionOverlays.cjs +1 -1
- package/dist/components/charts/Chromatogram/regionOverlays.cjs.map +1 -1
- package/dist/components/charts/Chromatogram/regionOverlays.js +11 -11
- package/dist/components/charts/Chromatogram/regionOverlays.js.map +1 -1
- package/dist/components/charts/Chromatogram/types.d.ts +4 -2
- package/dist/components/charts/Electropherogram/Electropherogram.cjs +1 -1
- package/dist/components/charts/Electropherogram/Electropherogram.cjs.map +1 -1
- package/dist/components/charts/Electropherogram/Electropherogram.js +84 -83
- package/dist/components/charts/Electropherogram/Electropherogram.js.map +1 -1
- package/dist/components/charts/Histogram/Histogram.cjs +1 -1
- package/dist/components/charts/Histogram/Histogram.cjs.map +1 -1
- package/dist/components/charts/Histogram/Histogram.js +42 -42
- package/dist/components/charts/Histogram/Histogram.js.map +1 -1
- package/dist/components/charts/ScatterPlotInteractive/ScatterPlotInteractive.cjs +1 -1
- package/dist/components/charts/ScatterPlotInteractive/ScatterPlotInteractive.cjs.map +1 -1
- package/dist/components/charts/ScatterPlotInteractive/ScatterPlotInteractive.js +4 -5
- package/dist/components/charts/ScatterPlotInteractive/ScatterPlotInteractive.js.map +1 -1
- package/dist/components/charts/chart-scale.cjs +2 -0
- package/dist/components/charts/chart-scale.cjs.map +1 -0
- package/dist/components/charts/chart-scale.d.ts +61 -0
- package/dist/components/charts/chart-scale.js +61 -0
- package/dist/components/charts/chart-scale.js.map +1 -0
- package/dist/index.css +1 -1
- package/dist/index.scoped.css +6 -0
- package/dist/index.tailwind.css +1 -1
- package/dist/ui/skeleton.cjs +1 -1
- package/dist/ui/skeleton.cjs.map +1 -1
- package/dist/ui/skeleton.js +1 -1
- package/dist/ui/skeleton.js.map +1 -1
- package/package.json +8 -2
package/README.md
CHANGED
|
@@ -135,16 +135,35 @@ This library uses **Tailwind CSS 4** with design tokens defined as CSS custom pr
|
|
|
135
135
|
|
|
136
136
|
### CSS Import Options
|
|
137
137
|
|
|
138
|
-
| Import path | Use case
|
|
139
|
-
| ------------------------------------------------------------ |
|
|
140
|
-
| `@tetrascience-npm/tetrascience-react-ui/index.css` | **Pre-built CSS** —
|
|
141
|
-
| `@tetrascience-npm/tetrascience-react-ui/index.tailwind.css` | **Tailwind source** — for apps that run their own Tailwind build and want to extend/override tokens.
|
|
142
|
-
|
|
143
|
-
|
|
138
|
+
| Import path | Use case |
|
|
139
|
+
| ------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
140
|
+
| `@tetrascience-npm/tetrascience-react-ui/index.css` | **Pre-built CSS** — for an app that owns its document. Import once at your app root. |
|
|
141
|
+
| `@tetrascience-npm/tetrascience-react-ui/index.tailwind.css` | **Tailwind source** — for apps that run their own Tailwind build and want to extend/override tokens. |
|
|
142
|
+
| `@tetrascience-npm/tetrascience-react-ui/index.scoped.css` | **Scoped CSS** — for code that renders inside a document it does _not_ own (a microfrontend remote, an embedded widget). See [Embedding in a host page](#embedding-in-a-host-page). |
|
|
143
|
+
|
|
144
|
+
Most consumers only need `index.css`.
|
|
145
|
+
|
|
146
|
+
#### What the stylesheet does — and does not — claim
|
|
147
|
+
|
|
148
|
+
Every selector rule the kit writes itself — its design tokens and its component CSS — ships
|
|
149
|
+
inside a `ts-ui-kit` cascade layer, and no published stylesheet contains an unlayered rule.
|
|
150
|
+
(Tailwind utilities land in Tailwind's `utilities` layer; `@font-face`, `@keyframes` and
|
|
151
|
+
`@property` are not selector-matched and stay top-level, with kit keyframes `ts-`-prefixed.)
|
|
152
|
+
That has two consequences worth knowing:
|
|
153
|
+
|
|
154
|
+
- **Your CSS always wins.** An unlayered rule outranks a layered one regardless of specificity or
|
|
155
|
+
load order, so a plain `:root { --primary: … }` in your app overrides the kit's token whether it
|
|
156
|
+
is written before or after the import. There is no ordering dance.
|
|
157
|
+
- **The kit never restyles your page by accident.** Its component class names are namespaced
|
|
158
|
+
(`.histogram-legend-divider`, `.platemap-legend__item`, …), and its tokens and Tailwind's
|
|
159
|
+
preflight reset are layered beneath anything you write. A CI gate
|
|
160
|
+
(`yarn check:css-leaks`) fails the build if any published stylesheet regains an unlayered rule.
|
|
144
161
|
|
|
145
162
|
### Theming
|
|
146
163
|
|
|
147
|
-
The design system is controlled via CSS custom properties
|
|
164
|
+
The design system is controlled via CSS custom properties. Override them anywhere in your own CSS
|
|
165
|
+
to customise colours, spacing, and radii — because the kit's tokens are layered, your unlayered
|
|
166
|
+
declaration wins in any order:
|
|
148
167
|
|
|
149
168
|
```css
|
|
150
169
|
:root {
|
|
@@ -156,6 +175,45 @@ The design system is controlled via CSS custom properties in `index.css`. Overri
|
|
|
156
175
|
|
|
157
176
|
Dark mode is supported via the `.dark` class on a parent element. See [THEMING.md](./THEMING.md) for details.
|
|
158
177
|
|
|
178
|
+
### Embedding in a host page
|
|
179
|
+
|
|
180
|
+
`index.css` is written for an app that owns its document: tokens on `:root` / `.dark`, Tailwind's
|
|
181
|
+
preflight on `html` / `body` / `*`. Inside someone else's document — a Module Federation remote
|
|
182
|
+
mounted into the TetraScience platform shell, a widget dropped into a legacy page — those are not
|
|
183
|
+
the kit's claims to make, even layered: a host that never declared `--surface-bright` would still
|
|
184
|
+
pick the kit's value up document-wide.
|
|
185
|
+
|
|
186
|
+
`index.scoped.css` is the same stylesheet with every rule in the `ts-ui-kit` and `base` layers
|
|
187
|
+
— tokens, component CSS, preflight — confined to an element carrying `data-ts-ui-root`. Import
|
|
188
|
+
it instead of `index.css` and mark your shell:
|
|
189
|
+
|
|
190
|
+
```tsx
|
|
191
|
+
import "@tetrascience-npm/tetrascience-react-ui/index.scoped.css";
|
|
192
|
+
|
|
193
|
+
export function App() {
|
|
194
|
+
return (
|
|
195
|
+
<div data-ts-ui-root className="dark">
|
|
196
|
+
{/* kit components render with their own tokens and reset in here… */}
|
|
197
|
+
</div>
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Two things to know when you use it:
|
|
203
|
+
|
|
204
|
+
- **Portaled surfaces need the marker too.** `Dialog`, `Popover`, `Select`, `Tooltip` and the
|
|
205
|
+
other overlay components render their content into `document.body`, outside your shell. Put
|
|
206
|
+
`data-ts-ui-root` on their `*Content` element as well (a thin wrapper component around each one
|
|
207
|
+
you use is the usual pattern), or they render with the host's tokens instead of the kit's.
|
|
208
|
+
- **Dark mode still keys off `.dark`.** `.dark` on `<html>` (or anything above the marker), on the
|
|
209
|
+
marked element itself, or on a dark panel nested inside a light shell all work — the scoped
|
|
210
|
+
rules are emitted as `.dark [data-ts-ui-root]`, `[data-ts-ui-root].dark` and
|
|
211
|
+
`[data-ts-ui-root] .dark`.
|
|
212
|
+
|
|
213
|
+
Tailwind's own `theme`, `properties`, `components` and `utilities` layers are left global in the
|
|
214
|
+
scoped build: they are keyed on Tailwind class names, your unlayered CSS already outranks them,
|
|
215
|
+
and confining `theme` would strip `--spacing` / `--radius-*` from portaled content.
|
|
216
|
+
|
|
159
217
|
## Components
|
|
160
218
|
|
|
161
219
|
### UI Primitives (`ui/`)
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const Q=require("react/jsx-runtime"),r=require("react"),L=require("../chart-scale.cjs"),lt=require("../ChartTooltip/ChartTooltip.cjs"),I=require("../plotly-loader.cjs"),ct=require("../../../hooks/use-element-size.cjs"),m=require("../../../hooks/use-plotly-theme.cjs"),st=require("../../../lib/utils.cjs"),Z=require("../../../utils/colors.cjs"),at=require("../ChartTooltip/lines.cjs"),ut=({dataSeries:f,width:q,height:H,xRange:p,yRange:x,variant:k="normal",xTitle:z,yTitle:v,title:w,xTickText:T})=>{const d=r.useRef(null),i=m.usePlotlyTheme(),[$,O]=ct.useElementSize(),h=q??O.width,s=H??O.height,V=h>0&&s>0,tt=q===void 0,et=H===void 0,o=L.resolveChartScale(h,s),A=w?o.margin.tTitle:o.margin.tNoTitle,C=r.useRef({width:h,height:s});C.current={width:h,height:s};const F=r.useRef(!1),_=r.useRef({width:0,height:0}),{bindTooltip:X,tooltipElement:ot}=lt.useChartTooltip({getLines:e=>at.chartTooltipLines(e.map(t=>typeof t.customdata=="number"?{...t,y:t.customdata}:t),{xLabel:z,yLabel:v})}),{xMin:j,xMax:B,yMin:U,yMax:K}=r.useMemo(()=>{let e=Number.MAX_VALUE,t=Number.MIN_VALUE,c=Number.MAX_VALUE,n=Number.MIN_VALUE;f.forEach(u=>{u.x.forEach(a=>{e=Math.min(e,a),t=Math.max(t,a)}),u.y.forEach(a=>{c=Math.min(c,a),n=Math.max(n,a)})});const M=(t-e)*.1,l=(n-c)*.1;return{xMin:e-M,xMax:t+M,yMin:k==="stacked"?0:c-l,yMax:n+l}},[f,k]),g=r.useMemo(()=>p||[j,B],[p,j,B]),y=r.useMemo(()=>x||[U,K],[x,U,K]),W=r.useMemo(()=>{const e=g[1]-g[0];let t=Math.pow(10,Math.floor(Math.log10(e)));e/t>10&&(t=t*2),e/t<4&&(t=t/2);const c=[];let n=Math.ceil(g[0]/t)*t;for(;n<=g[1];)c.push(n),n+=t;return c},[g]),b=r.useMemo(()=>{const e=y[1]-y[0];let t=Math.pow(10,Math.floor(Math.log10(e)));e/t>10&&(t=t*2),e/t<4&&(t=t/2);const c=[];let n=Math.ceil(y[0]/t)*t;for(;n<=y[1];)c.push(n),n+=t;return c},[y]),E=r.useMemo(()=>[...new Set(f.flatMap(e=>e.x))].sort((e,t)=>e-t),[f]),N=!!T&&T.length===E.length,R=r.useMemo(()=>L.thinTicks(b,L.maxTickCount(s-A-o.margin.b,o.tickFontSize*L.Y_TICK_LABEL_SPACING)),[b,s,A,o]),rt=R.join(","),S=r.useRef(R);S.current=R;const P=r.useMemo(()=>({tickcolor:i.tickColor,ticklen:o.ticklen,tickwidth:1,ticks:"outside",tickfont:{size:o.tickFontSize,color:i.textColor,family:m.CHART_FONT_FAMILY,weight:400},linecolor:i.lineColor,linewidth:1,position:0,zeroline:!1}),[i,o]),Y=r.useMemo(()=>w?{text:w,x:.5,y:.95,xanchor:"center",yanchor:"top",font:{size:o.titleFontSize,weight:600,family:m.CHART_FONT_FAMILY,color:i.textColor,lineheight:1.2,standoff:30}}:void 0,[w,i,o]);return r.useEffect(()=>{if(!d.current||!V)return;let e;if(k==="stacked"){const l=new Array(f[0]?.x.length||0).fill(0);e=f.map((u,a)=>{const nt=u.y.map((it,G)=>{const J=l[G]+it;return l[G]=J,J}),D=Z.seriesColor(a,u.color);return{x:u.x,y:nt,customdata:u.y,type:"scatter",mode:"lines",name:u.name,hoverinfo:"none",fill:a===0?"tozeroy":"tonexty",fillcolor:D,line:{color:D,width:2}}})}else e=f.map((l,u)=>{const a=Z.seriesColor(u,l.color);return{x:l.x,y:l.y,type:"scatter",mode:"lines",name:l.name,hoverinfo:"none",fill:l.fill||"tozeroy",fillcolor:a,line:{color:a,width:2}}});const t={width:C.current.width,height:C.current.height,...Y?{title:Y}:{},margin:{l:o.margin.l,r:o.margin.r,b:o.margin.b,t:A,pad:0},paper_bgcolor:i.paperBg,plot_bgcolor:i.plotBg,font:{family:m.CHART_FONT_FAMILY},dragmode:!1,xaxis:{title:{text:z,font:{size:o.axisTitleFontSize,color:i.textSecondary,family:m.CHART_FONT_FAMILY,weight:400},standoff:o.axisTitleStandoff},gridcolor:i.gridColor,range:p,autorange:!p,tickmode:"array",tickvals:N?E:W,...N?{ticktext:T}:{},showgrid:!0,automargin:!0,...P},yaxis:{title:{text:v,font:{size:o.axisTitleFontSize,color:i.textSecondary,family:m.CHART_FONT_FAMILY,weight:400},standoff:o.axisTitleStandoff},gridcolor:i.gridColor,range:x,autorange:!x,tickmode:"array",tickvals:S.current,showgrid:!0,automargin:!0,...P},legend:{x:.5,y:0,xanchor:"center",yanchor:"bottom",yref:"container",orientation:"h",font:{size:o.legendFontSize,color:i.legendColor,family:m.CHART_FONT_FAMILY,weight:500,lineheight:o.legendLineHeight}},showlegend:!0},c={responsive:!1,displayModeBar:!1,displaylogo:!1};let n=!1,M=null;return I.loadPlotly().then(l=>{n||!d.current||(l.newPlot(d.current,e,t,c),X(d.current),M=d.current,F.current=!0,_.current={...C.current})}),()=>{n=!0,M&&(I.getLoadedPlotly().purge(M),F.current=!1)}},[f,V,p,x,g,y,k,z,v,w,Y,P,W,b,E,N,T,i,o,A,X]),r.useEffect(()=>{const e=d.current;!e||!F.current||h<=0||s<=0||_.current.width===h&&_.current.height===s||(_.current={width:h,height:s},I.getLoadedPlotly().relayout(e,{width:h,height:s,"yaxis.tickvals":S.current}).catch(()=>{}))},[h,s,rt]),Q.jsxs("div",{ref:$,className:st.cn("area-graph-container relative",tt&&"w-full",et&&"h-full"),children:[Q.jsx("div",{ref:d,style:{width:"100%",height:"100%"}}),ot]})};exports.AreaPlot=ut;
|
|
2
2
|
//# sourceMappingURL=AreaPlot.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AreaPlot.cjs","sources":["../../../../src/components/charts/AreaPlot/AreaPlot.tsx"],"sourcesContent":["import React, { useEffect, useRef, useMemo } from \"react\";\n\nimport { chartTooltipLines, useChartTooltip } from \"../ChartTooltip\";\nimport { getLoadedPlotly, loadPlotly } from \"../plotly-loader\";\n\nimport { useElementSize } from \"@/hooks/use-element-size\";\nimport { CHART_FONT_FAMILY, usePlotlyTheme } from \"@/hooks/use-plotly-theme\";\nimport { cn } from \"@/lib/utils\";\nimport { seriesColor } from \"@/utils/colors\";\n\ninterface AreaDataSeries {\n x: number[];\n y: number[];\n name: string;\n /** Optional color override (auto-assigned from CHART_COLORS if not provided) */\n color?: string;\n fill?: \"tozeroy\" | \"tonexty\" | \"toself\";\n}\n\ntype AreaPlotVariant = \"normal\" | \"stacked\";\n\n/** Top margin reserving room for the 32px title; reduced when no title is set */\nconst TITLE_MARGIN_TOP = 80;\nconst NO_TITLE_MARGIN_TOP = 40;\n\ninterface AreaPlotProps {\n dataSeries: AreaDataSeries[];\n /**\n * Fixed width in pixels. When omitted, the chart fills its container and\n * tracks the container's width via a `ResizeObserver`.\n */\n width?: number;\n /**\n * Fixed height in pixels. When omitted, the chart fills its container and\n * tracks the container's height via a `ResizeObserver`.\n */\n height?: number;\n xRange?: [number, number];\n yRange?: [number, number];\n variant?: AreaPlotVariant;\n xTitle?: string;\n yTitle?: string;\n title?: string;\n /**\n * Categorical labels for the x-axis ticks. When provided, the x data values\n * still drive area positioning but the displayed tick labels match these\n * strings in order (e.g. [\"Mon\", \"Tue\", …]). Should align 1:1 with the\n * unique, ordered x values across all series.\n */\n xTickText?: string[];\n}\n\nconst AreaPlot: React.FC<AreaPlotProps> = ({\n dataSeries,\n width,\n height,\n xRange,\n yRange,\n variant = \"normal\",\n xTitle,\n yTitle,\n title,\n xTickText,\n}) => {\n const plotRef = useRef<HTMLDivElement>(null);\n const theme = usePlotlyTheme();\n\n // When width/height are omitted the chart fills its container; otherwise the\n // explicit pixel size wins. The container is measured either way (cheap) but\n // only used as the resolved size for the omitted dimension(s).\n const [containerRef, measured] = useElementSize<HTMLDivElement>();\n const resolvedWidth = width ?? measured.width;\n const resolvedHeight = height ?? measured.height;\n const hasSize = resolvedWidth > 0 && resolvedHeight > 0;\n // Fill is per-dimension: omit width to fill the container width, omit height\n // to fill its height (so e.g. a fixed width with a container-driven height works).\n const fillWidth = width === undefined;\n const fillHeight = height === undefined;\n\n // Hold the latest resolved size in a ref so the newPlot effect can read it\n // without listing it as a dependency — size changes are handled by a\n // separate relayout effect rather than by tearing down and recreating the plot.\n const sizeRef = useRef({ width: resolvedWidth, height: resolvedHeight });\n sizeRef.current = { width: resolvedWidth, height: resolvedHeight };\n const plotInitedRef = useRef(false);\n // Size last applied to the plot, so the resize effect can skip a redundant\n // relayout right after newPlot already drew at that size.\n const appliedSizeRef = useRef({ width: 0, height: 0 });\n const { bindTooltip, tooltipElement } = useChartTooltip({\n // Stacked traces carry the original series values as customdata;\n // display those instead of the cumulative stack heights\n getLines: (points) =>\n chartTooltipLines(\n points.map((point) =>\n typeof point.customdata === \"number\"\n ? { ...point, y: point.customdata }\n : point,\n ),\n { xLabel: xTitle, yLabel: yTitle },\n ),\n });\n\n const { xMin, xMax, yMin, yMax } = useMemo(() => {\n let minX = Number.MAX_VALUE;\n let maxX = Number.MIN_VALUE;\n let minY = Number.MAX_VALUE;\n let maxY = Number.MIN_VALUE;\n\n dataSeries.forEach((series) => {\n series.x.forEach((x) => {\n minX = Math.min(minX, x);\n maxX = Math.max(maxX, x);\n });\n series.y.forEach((y) => {\n minY = Math.min(minY, y);\n maxY = Math.max(maxY, y);\n });\n });\n\n const xPadding = (maxX - minX) * 0.1;\n const yPadding = (maxY - minY) * 0.1;\n\n return {\n xMin: minX - xPadding,\n xMax: maxX + xPadding,\n yMin: variant === \"stacked\" ? 0 : minY - yPadding,\n yMax: maxY + yPadding,\n };\n }, [dataSeries, variant]);\n\n const effectiveXRange = useMemo(\n () => xRange || [xMin, xMax],\n [xRange, xMin, xMax],\n );\n const effectiveYRange = useMemo(\n () => yRange || [yMin, yMax],\n [yRange, yMin, yMax],\n );\n\n const xTicks = useMemo(() => {\n const range = effectiveXRange[1] - effectiveXRange[0];\n let step = Math.pow(10, Math.floor(Math.log10(range)));\n\n if (range / step > 10) step = step * 2;\n if (range / step < 4) step = step / 2;\n\n const ticks = [];\n let current = Math.ceil(effectiveXRange[0] / step) * step;\n while (current <= effectiveXRange[1]) {\n ticks.push(current);\n current += step;\n }\n return ticks;\n }, [effectiveXRange]);\n\n const yTicks = useMemo(() => {\n const range = effectiveYRange[1] - effectiveYRange[0];\n let step = Math.pow(10, Math.floor(Math.log10(range)));\n\n if (range / step > 10) step = step * 2;\n if (range / step < 4) step = step / 2;\n\n const ticks = [];\n let current = Math.ceil(effectiveYRange[0] / step) * step;\n while (current <= effectiveYRange[1]) {\n ticks.push(current);\n current += step;\n }\n return ticks;\n }, [effectiveYRange]);\n\n // When categorical labels are supplied, ticks must sit on the actual data\n // x-positions rather than the computed nice-step values above. Sorted\n // ascending so labels map deterministically to x regardless of series order.\n const xDataValues = useMemo(\n () => [...new Set(dataSeries.flatMap((s) => s.x))].sort((a, b) => a - b),\n [dataSeries],\n );\n\n // Only apply categorical labels when they align 1:1 with the tick positions;\n // a mismatch would silently mis-label ticks, so fall back to numeric ticks.\n const useCategoricalX = !!xTickText && xTickText.length === xDataValues.length;\n\n const tickOptions = useMemo(\n () => ({\n tickcolor: theme.tickColor,\n ticklen: 12,\n tickwidth: 1,\n ticks: \"outside\" as const,\n tickfont: {\n size: 16,\n color: theme.textColor,\n family: CHART_FONT_FAMILY,\n weight: 400,\n },\n linecolor: theme.lineColor,\n linewidth: 1,\n position: 0,\n zeroline: false,\n }),\n [theme],\n );\n\n const titleOptions = useMemo(\n () =>\n title\n ? {\n text: title,\n x: 0.5,\n y: 0.95,\n xanchor: \"center\" as const,\n yanchor: \"top\" as const,\n font: {\n size: 32,\n weight: 600,\n family: CHART_FONT_FAMILY,\n color: theme.textColor,\n lineheight: 1.2,\n standoff: 30,\n },\n }\n : undefined,\n [title, theme],\n );\n\n useEffect(() => {\n if (!plotRef.current || !hasSize) return;\n\n let data;\n\n if (variant === \"stacked\") {\n // For stacked mode, we need to calculate cumulative values\n const cumulativeY = new Array(dataSeries[0]?.x.length || 0).fill(0);\n\n data = dataSeries.map((series, index) => {\n // Calculate cumulative values for this series\n const stackedY = series.y.map((value, i) => {\n const result = cumulativeY[i] + value;\n cumulativeY[i] = result;\n return result;\n });\n\n const color = seriesColor(index, series.color);\n return {\n x: series.x,\n y: stackedY,\n // Tooltips report the series' own values, not the stacked sums\n customdata: series.y,\n type: \"scatter\" as const,\n mode: \"lines\" as const,\n name: series.name,\n hoverinfo: \"none\" as const,\n fill: index === 0 ? (\"tozeroy\" as const) : (\"tonexty\" as const),\n fillcolor: color,\n line: {\n color,\n width: 2,\n },\n };\n });\n } else {\n // Normal mode - each area fills independently from zero\n data = dataSeries.map((series, index) => {\n const color = seriesColor(index, series.color);\n return {\n x: series.x,\n y: series.y,\n type: \"scatter\" as const,\n mode: \"lines\" as const,\n name: series.name,\n hoverinfo: \"none\" as const,\n fill: series.fill || (\"tozeroy\" as const),\n fillcolor: color,\n line: {\n color,\n width: 2,\n },\n };\n });\n }\n\n const layout = {\n width: sizeRef.current.width,\n height: sizeRef.current.height,\n ...(titleOptions ? { title: titleOptions } : {}),\n margin: {\n l: 80,\n r: 40,\n // Reserve room for tick labels, the x-axis title, and the\n // container-anchored bottom legend stacked beneath them.\n b: 96,\n t: title ? TITLE_MARGIN_TOP : NO_TITLE_MARGIN_TOP,\n pad: 0,\n },\n paper_bgcolor: theme.paperBg,\n plot_bgcolor: theme.plotBg,\n font: {\n family: CHART_FONT_FAMILY,\n },\n dragmode: false as const,\n xaxis: {\n title: {\n text: xTitle,\n font: {\n size: 16,\n color: theme.textSecondary,\n family: CHART_FONT_FAMILY,\n weight: 400,\n },\n standoff: 15,\n },\n gridcolor: theme.gridColor,\n range: xRange,\n autorange: !xRange,\n tickmode: \"array\" as const,\n tickvals: useCategoricalX ? xDataValues : xTicks,\n ...(useCategoricalX ? { ticktext: xTickText } : {}),\n showgrid: true,\n // Reserve space for tick labels + the axis title so the bottom legend\n // can't overlap them at small sizes (SW-2157).\n automargin: true,\n ...tickOptions,\n },\n yaxis: {\n title: {\n text: yTitle,\n font: {\n size: 16,\n color: theme.textSecondary,\n family: CHART_FONT_FAMILY,\n weight: 400,\n },\n standoff: 15,\n },\n gridcolor: theme.gridColor,\n range: yRange,\n autorange: !yRange,\n tickmode: \"array\" as const,\n tickvals: yTicks,\n showgrid: true,\n automargin: true,\n ...tickOptions,\n },\n legend: {\n // Anchor to the bottom of the container (not the plot area) so the\n // legend always clears the x-axis tick labels + title — a paper-relative\n // fractional offset collapses into the ticks at small heights (SW-2157).\n x: 0.5,\n y: 0,\n xanchor: \"center\" as const,\n yanchor: \"bottom\" as const,\n yref: \"container\" as const,\n orientation: \"h\" as const,\n font: {\n size: 13,\n color: theme.legendColor,\n family: CHART_FONT_FAMILY,\n weight: 500,\n lineheight: 18,\n },\n },\n showlegend: true,\n };\n\n const config = {\n // We drive sizing explicitly from the measured container, so Plotly's own\n // window-resize responsiveness is disabled (it can't see container resizes).\n responsive: false,\n displayModeBar: false,\n displaylogo: false,\n };\n\n // Plotly is loaded lazily so it stays out of the consumer's main chunk\n // (SW-2007); the draw is skipped if the effect re-runs or unmounts first.\n let cancelled = false;\n let plotElement: HTMLDivElement | null = null;\n void loadPlotly().then((plotly) => {\n if (cancelled || !plotRef.current) return;\n plotly.newPlot(plotRef.current, data, layout, config);\n bindTooltip(plotRef.current);\n\n // Capture ref value for cleanup\n plotElement = plotRef.current;\n plotInitedRef.current = true;\n appliedSizeRef.current = { ...sizeRef.current };\n });\n\n return () => {\n cancelled = true;\n if (plotElement) {\n getLoadedPlotly().purge(plotElement);\n plotInitedRef.current = false;\n }\n };\n }, [dataSeries, hasSize, xRange, yRange, effectiveXRange, effectiveYRange, variant, xTitle, yTitle, title, titleOptions, tickOptions, xTicks, yTicks, xDataValues, useCategoricalX, xTickText, theme, bindTooltip]);\n\n // Resize in place when the measured/overridden size changes — far cheaper\n // than recreating the plot (and it preserves tooltip/event bindings).\n useEffect(() => {\n const plotElement = plotRef.current;\n if (!plotElement || !plotInitedRef.current || resolvedWidth <= 0 || resolvedHeight <= 0) {\n return;\n }\n // newPlot already drew at the current size; skip the redundant relayout\n // (it would queue an automargin redraw that can reject if we unmount first).\n if (\n appliedSizeRef.current.width === resolvedWidth &&\n appliedSizeRef.current.height === resolvedHeight\n ) {\n return;\n }\n appliedSizeRef.current = { width: resolvedWidth, height: resolvedHeight };\n // Swallow rejections from a relayout that races an unmount/purge.\n // plotInitedRef guarantees Plotly finished loading, so sync access is safe.\n void getLoadedPlotly()\n .relayout(plotElement, { width: resolvedWidth, height: resolvedHeight })\n .catch(() => {});\n }, [resolvedWidth, resolvedHeight]);\n\n return (\n <div\n ref={containerRef}\n className={cn(\"area-graph-container relative\", fillWidth && \"w-full\", fillHeight && \"h-full\")}\n >\n <div ref={plotRef} style={{ width: \"100%\", height: \"100%\" }} />\n {tooltipElement}\n </div>\n );\n};\n\nexport { AreaPlot };\nexport type { AreaDataSeries, AreaPlotVariant, AreaPlotProps };\n"],"names":["TITLE_MARGIN_TOP","NO_TITLE_MARGIN_TOP","AreaPlot","dataSeries","width","height","xRange","yRange","variant","xTitle","yTitle","title","xTickText","plotRef","useRef","theme","usePlotlyTheme","containerRef","measured","useElementSize","resolvedWidth","resolvedHeight","hasSize","fillWidth","fillHeight","sizeRef","plotInitedRef","appliedSizeRef","bindTooltip","tooltipElement","useChartTooltip","points","chartTooltipLines","point","xMin","xMax","yMin","yMax","useMemo","minX","maxX","minY","maxY","series","x","y","xPadding","yPadding","effectiveXRange","effectiveYRange","xTicks","range","step","ticks","current","yTicks","xDataValues","s","a","b","useCategoricalX","tickOptions","CHART_FONT_FAMILY","titleOptions","useEffect","data","cumulativeY","index","stackedY","value","i","result","color","seriesColor","layout","config","cancelled","plotElement","loadPlotly","plotly","getLoadedPlotly","jsxs","cn","jsx"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AreaPlot.cjs","sources":["../../../../src/components/charts/AreaPlot/AreaPlot.tsx"],"sourcesContent":["import React, { useEffect, useRef, useMemo } from \"react\";\n\nimport { Y_TICK_LABEL_SPACING, maxTickCount, resolveChartScale, thinTicks } from \"../chart-scale\";\nimport { chartTooltipLines, useChartTooltip } from \"../ChartTooltip\";\nimport { getLoadedPlotly, loadPlotly } from \"../plotly-loader\";\n\nimport type Plotly from \"plotly.js-dist\";\n\nimport { useElementSize } from \"@/hooks/use-element-size\";\nimport { CHART_FONT_FAMILY, usePlotlyTheme } from \"@/hooks/use-plotly-theme\";\nimport { cn } from \"@/lib/utils\";\nimport { seriesColor } from \"@/utils/colors\";\n\ninterface AreaDataSeries {\n x: number[];\n y: number[];\n name: string;\n /** Optional color override (auto-assigned from CHART_COLORS if not provided) */\n color?: string;\n fill?: \"tozeroy\" | \"tonexty\" | \"toself\";\n}\n\ntype AreaPlotVariant = \"normal\" | \"stacked\";\n\ninterface AreaPlotProps {\n dataSeries: AreaDataSeries[];\n /**\n * Fixed width in pixels. When omitted, the chart fills its container and\n * tracks the container's width via a `ResizeObserver`.\n */\n width?: number;\n /**\n * Fixed height in pixels. When omitted, the chart fills its container and\n * tracks the container's height via a `ResizeObserver`.\n */\n height?: number;\n xRange?: [number, number];\n yRange?: [number, number];\n variant?: AreaPlotVariant;\n xTitle?: string;\n yTitle?: string;\n title?: string;\n /**\n * Categorical labels for the x-axis ticks. When provided, the x data values\n * still drive area positioning but the displayed tick labels match these\n * strings in order (e.g. [\"Mon\", \"Tue\", …]). Should align 1:1 with the\n * unique, ordered x values across all series.\n */\n xTickText?: string[];\n}\n\nconst AreaPlot: React.FC<AreaPlotProps> = ({\n dataSeries,\n width,\n height,\n xRange,\n yRange,\n variant = \"normal\",\n xTitle,\n yTitle,\n title,\n xTickText,\n}) => {\n const plotRef = useRef<HTMLDivElement>(null);\n const theme = usePlotlyTheme();\n\n // When width/height are omitted the chart fills its container; otherwise the\n // explicit pixel size wins. The container is measured either way (cheap) but\n // only used as the resolved size for the omitted dimension(s).\n const [containerRef, measured] = useElementSize<HTMLDivElement>();\n const resolvedWidth = width ?? measured.width;\n const resolvedHeight = height ?? measured.height;\n const hasSize = resolvedWidth > 0 && resolvedHeight > 0;\n // Fill is per-dimension: omit width to fill the container width, omit height\n // to fill its height (so e.g. a fixed width with a container-driven height works).\n const fillWidth = width === undefined;\n const fillHeight = height === undefined;\n // Fonts, tick length and margins step down on small canvases so the plot\n // area (not the chrome) gets the pixels (SW-2298).\n const scale = resolveChartScale(resolvedWidth, resolvedHeight);\n const marginTop = title ? scale.margin.tTitle : scale.margin.tNoTitle;\n\n // Hold the latest resolved size in a ref so the newPlot effect can read it\n // without listing it as a dependency — size changes are handled by a\n // separate relayout effect rather than by tearing down and recreating the plot.\n const sizeRef = useRef({ width: resolvedWidth, height: resolvedHeight });\n sizeRef.current = { width: resolvedWidth, height: resolvedHeight };\n const plotInitedRef = useRef(false);\n // Size last applied to the plot, so the resize effect can skip a redundant\n // relayout right after newPlot already drew at that size.\n const appliedSizeRef = useRef({ width: 0, height: 0 });\n const { bindTooltip, tooltipElement } = useChartTooltip({\n // Stacked traces carry the original series values as customdata;\n // display those instead of the cumulative stack heights\n getLines: (points) =>\n chartTooltipLines(\n points.map((point) =>\n typeof point.customdata === \"number\"\n ? { ...point, y: point.customdata }\n : point,\n ),\n { xLabel: xTitle, yLabel: yTitle },\n ),\n });\n\n const { xMin, xMax, yMin, yMax } = useMemo(() => {\n let minX = Number.MAX_VALUE;\n let maxX = Number.MIN_VALUE;\n let minY = Number.MAX_VALUE;\n let maxY = Number.MIN_VALUE;\n\n dataSeries.forEach((series) => {\n series.x.forEach((x) => {\n minX = Math.min(minX, x);\n maxX = Math.max(maxX, x);\n });\n series.y.forEach((y) => {\n minY = Math.min(minY, y);\n maxY = Math.max(maxY, y);\n });\n });\n\n const xPadding = (maxX - minX) * 0.1;\n const yPadding = (maxY - minY) * 0.1;\n\n return {\n xMin: minX - xPadding,\n xMax: maxX + xPadding,\n yMin: variant === \"stacked\" ? 0 : minY - yPadding,\n yMax: maxY + yPadding,\n };\n }, [dataSeries, variant]);\n\n const effectiveXRange = useMemo(\n () => xRange || [xMin, xMax],\n [xRange, xMin, xMax],\n );\n const effectiveYRange = useMemo(\n () => yRange || [yMin, yMax],\n [yRange, yMin, yMax],\n );\n\n const xTicks = useMemo(() => {\n const range = effectiveXRange[1] - effectiveXRange[0];\n let step = Math.pow(10, Math.floor(Math.log10(range)));\n\n if (range / step > 10) step = step * 2;\n if (range / step < 4) step = step / 2;\n\n const ticks = [];\n let current = Math.ceil(effectiveXRange[0] / step) * step;\n while (current <= effectiveXRange[1]) {\n ticks.push(current);\n current += step;\n }\n return ticks;\n }, [effectiveXRange]);\n\n const yTicks = useMemo(() => {\n const range = effectiveYRange[1] - effectiveYRange[0];\n let step = Math.pow(10, Math.floor(Math.log10(range)));\n\n if (range / step > 10) step = step * 2;\n if (range / step < 4) step = step / 2;\n\n const ticks = [];\n let current = Math.ceil(effectiveYRange[0] / step) * step;\n while (current <= effectiveYRange[1]) {\n ticks.push(current);\n current += step;\n }\n return ticks;\n }, [effectiveYRange]);\n\n // When categorical labels are supplied, ticks must sit on the actual data\n // x-positions rather than the computed nice-step values above. Sorted\n // ascending so labels map deterministically to x regardless of series order.\n const xDataValues = useMemo(\n () => [...new Set(dataSeries.flatMap((s) => s.x))].sort((a, b) => a - b),\n [dataSeries],\n );\n\n // Only apply categorical labels when they align 1:1 with the tick positions;\n // a mismatch would silently mis-label ticks, so fall back to numeric ticks.\n const useCategoricalX = !!xTickText && xTickText.length === xDataValues.length;\n\n // Y ticks thinned to what fits the plot height. Derived from the resolved\n // (not last-plotted) height so an in-place resize also updates them via the\n // relayout effect below, instead of only when the scale bucket flips.\n const yTickVals = useMemo(\n () =>\n thinTicks(\n yTicks,\n maxTickCount(\n resolvedHeight - marginTop - scale.margin.b,\n scale.tickFontSize * Y_TICK_LABEL_SPACING,\n ),\n ),\n [yTicks, resolvedHeight, marginTop, scale],\n );\n const yTickKey = yTickVals.join(\",\");\n const yTickValsRef = useRef(yTickVals);\n yTickValsRef.current = yTickVals;\n\n const tickOptions = useMemo(\n () => ({\n tickcolor: theme.tickColor,\n ticklen: scale.ticklen,\n tickwidth: 1,\n ticks: \"outside\" as const,\n tickfont: {\n size: scale.tickFontSize,\n color: theme.textColor,\n family: CHART_FONT_FAMILY,\n weight: 400,\n },\n linecolor: theme.lineColor,\n linewidth: 1,\n position: 0,\n zeroline: false,\n }),\n [theme, scale],\n );\n\n const titleOptions = useMemo(\n () =>\n title\n ? {\n text: title,\n x: 0.5,\n y: 0.95,\n xanchor: \"center\" as const,\n yanchor: \"top\" as const,\n font: {\n size: scale.titleFontSize,\n weight: 600,\n family: CHART_FONT_FAMILY,\n color: theme.textColor,\n lineheight: 1.2,\n standoff: 30,\n },\n }\n : undefined,\n [title, theme, scale],\n );\n\n useEffect(() => {\n if (!plotRef.current || !hasSize) return;\n\n let data;\n\n if (variant === \"stacked\") {\n // For stacked mode, we need to calculate cumulative values\n const cumulativeY = new Array(dataSeries[0]?.x.length || 0).fill(0);\n\n data = dataSeries.map((series, index) => {\n // Calculate cumulative values for this series\n const stackedY = series.y.map((value, i) => {\n const result = cumulativeY[i] + value;\n cumulativeY[i] = result;\n return result;\n });\n\n const color = seriesColor(index, series.color);\n return {\n x: series.x,\n y: stackedY,\n // Tooltips report the series' own values, not the stacked sums\n customdata: series.y,\n type: \"scatter\" as const,\n mode: \"lines\" as const,\n name: series.name,\n hoverinfo: \"none\" as const,\n fill: index === 0 ? (\"tozeroy\" as const) : (\"tonexty\" as const),\n fillcolor: color,\n line: {\n color,\n width: 2,\n },\n };\n });\n } else {\n // Normal mode - each area fills independently from zero\n data = dataSeries.map((series, index) => {\n const color = seriesColor(index, series.color);\n return {\n x: series.x,\n y: series.y,\n type: \"scatter\" as const,\n mode: \"lines\" as const,\n name: series.name,\n hoverinfo: \"none\" as const,\n fill: series.fill || (\"tozeroy\" as const),\n fillcolor: color,\n line: {\n color,\n width: 2,\n },\n };\n });\n }\n\n const layout = {\n width: sizeRef.current.width,\n height: sizeRef.current.height,\n ...(titleOptions ? { title: titleOptions } : {}),\n margin: {\n l: scale.margin.l,\n r: scale.margin.r,\n // Reserve room for tick labels, the x-axis title, and the\n // container-anchored bottom legend stacked beneath them.\n b: scale.margin.b,\n t: marginTop,\n pad: 0,\n },\n paper_bgcolor: theme.paperBg,\n plot_bgcolor: theme.plotBg,\n font: {\n family: CHART_FONT_FAMILY,\n },\n dragmode: false as const,\n xaxis: {\n title: {\n text: xTitle,\n font: {\n size: scale.axisTitleFontSize,\n color: theme.textSecondary,\n family: CHART_FONT_FAMILY,\n weight: 400,\n },\n standoff: scale.axisTitleStandoff,\n },\n gridcolor: theme.gridColor,\n range: xRange,\n autorange: !xRange,\n tickmode: \"array\" as const,\n tickvals: useCategoricalX ? xDataValues : xTicks,\n ...(useCategoricalX ? { ticktext: xTickText } : {}),\n showgrid: true,\n // Reserve space for tick labels + the axis title so the bottom legend\n // can't overlap them at small sizes (SW-2157).\n automargin: true,\n ...tickOptions,\n },\n yaxis: {\n title: {\n text: yTitle,\n font: {\n size: scale.axisTitleFontSize,\n color: theme.textSecondary,\n family: CHART_FONT_FAMILY,\n weight: 400,\n },\n standoff: scale.axisTitleStandoff,\n },\n gridcolor: theme.gridColor,\n range: yRange,\n autorange: !yRange,\n tickmode: \"array\" as const,\n tickvals: yTickValsRef.current,\n showgrid: true,\n automargin: true,\n ...tickOptions,\n },\n legend: {\n // Anchor to the bottom of the container (not the plot area) so the\n // legend always clears the x-axis tick labels + title — a paper-relative\n // fractional offset collapses into the ticks at small heights (SW-2157).\n x: 0.5,\n y: 0,\n xanchor: \"center\" as const,\n yanchor: \"bottom\" as const,\n yref: \"container\" as const,\n orientation: \"h\" as const,\n font: {\n size: scale.legendFontSize,\n color: theme.legendColor,\n family: CHART_FONT_FAMILY,\n weight: 500,\n lineheight: scale.legendLineHeight,\n },\n },\n showlegend: true,\n };\n\n const config = {\n // We drive sizing explicitly from the measured container, so Plotly's own\n // window-resize responsiveness is disabled (it can't see container resizes).\n responsive: false,\n displayModeBar: false,\n displaylogo: false,\n };\n\n // Plotly is loaded lazily so it stays out of the consumer's main chunk\n // (SW-2007); the draw is skipped if the effect re-runs or unmounts first.\n let cancelled = false;\n let plotElement: HTMLDivElement | null = null;\n void loadPlotly().then((plotly) => {\n if (cancelled || !plotRef.current) return;\n plotly.newPlot(plotRef.current, data, layout, config);\n bindTooltip(plotRef.current);\n\n // Capture ref value for cleanup\n plotElement = plotRef.current;\n plotInitedRef.current = true;\n appliedSizeRef.current = { ...sizeRef.current };\n });\n\n return () => {\n cancelled = true;\n if (plotElement) {\n getLoadedPlotly().purge(plotElement);\n plotInitedRef.current = false;\n }\n };\n }, [dataSeries, hasSize, xRange, yRange, effectiveXRange, effectiveYRange, variant, xTitle, yTitle, title, titleOptions, tickOptions, xTicks, yTicks, xDataValues, useCategoricalX, xTickText, theme, scale, marginTop, bindTooltip]);\n\n // Resize in place when the measured/overridden size changes — far cheaper\n // than recreating the plot (and it preserves tooltip/event bindings).\n useEffect(() => {\n const plotElement = plotRef.current;\n if (!plotElement || !plotInitedRef.current || resolvedWidth <= 0 || resolvedHeight <= 0) {\n return;\n }\n // newPlot already drew at the current size; skip the redundant relayout\n // (it would queue an automargin redraw that can reject if we unmount first).\n if (\n appliedSizeRef.current.width === resolvedWidth &&\n appliedSizeRef.current.height === resolvedHeight\n ) {\n return;\n }\n appliedSizeRef.current = { width: resolvedWidth, height: resolvedHeight };\n // Swallow rejections from a relayout that races an unmount/purge.\n // plotInitedRef guarantees Plotly finished loading, so sync access is safe.\n void getLoadedPlotly()\n .relayout(plotElement, {\n width: resolvedWidth,\n height: resolvedHeight,\n // Re-thin the y ticks for the new plot height (SW-2298). The flattened\n // key is valid relayout input but not part of the Layout type.\n \"yaxis.tickvals\": yTickValsRef.current,\n } as Partial<Plotly.Layout>)\n .catch(() => {});\n }, [resolvedWidth, resolvedHeight, yTickKey]);\n\n return (\n <div\n ref={containerRef}\n className={cn(\"area-graph-container relative\", fillWidth && \"w-full\", fillHeight && \"h-full\")}\n >\n <div ref={plotRef} style={{ width: \"100%\", height: \"100%\" }} />\n {tooltipElement}\n </div>\n );\n};\n\nexport { AreaPlot };\nexport type { AreaDataSeries, AreaPlotVariant, AreaPlotProps };\n"],"names":["AreaPlot","dataSeries","width","height","xRange","yRange","variant","xTitle","yTitle","title","xTickText","plotRef","useRef","theme","usePlotlyTheme","containerRef","measured","useElementSize","resolvedWidth","resolvedHeight","hasSize","fillWidth","fillHeight","scale","resolveChartScale","marginTop","sizeRef","plotInitedRef","appliedSizeRef","bindTooltip","tooltipElement","useChartTooltip","points","chartTooltipLines","point","xMin","xMax","yMin","yMax","useMemo","minX","maxX","minY","maxY","series","x","y","xPadding","yPadding","effectiveXRange","effectiveYRange","xTicks","range","step","ticks","current","yTicks","xDataValues","s","a","b","useCategoricalX","yTickVals","thinTicks","maxTickCount","Y_TICK_LABEL_SPACING","yTickKey","yTickValsRef","tickOptions","CHART_FONT_FAMILY","titleOptions","useEffect","data","cumulativeY","index","stackedY","value","i","result","color","seriesColor","layout","config","cancelled","plotElement","loadPlotly","plotly","getLoadedPlotly","jsxs","cn","jsx"],"mappings":"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"}
|