@carto/ps-react-ui 4.22.0 → 4.23.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.
- package/dist/actions-D7LB9DvT.js +1161 -0
- package/dist/actions-D7LB9DvT.js.map +1 -0
- package/dist/category-Ca5XDx0N.js +839 -0
- package/dist/category-Ca5XDx0N.js.map +1 -0
- package/dist/{download-C7he8mSh.js → download--wRRnf19.js} +81 -80
- package/dist/download--wRRnf19.js.map +1 -0
- package/dist/{echart-BnJYXH7H.js → echart-CgOQw9XB.js} +3 -2
- package/dist/echart-CgOQw9XB.js.map +1 -0
- package/dist/{formula-Cqj84ZGX.js → formula-DRuMIVo8.js} +6 -6
- package/dist/formula-DRuMIVo8.js.map +1 -0
- package/dist/{markdown-CV_KP-at.js → markdown-C3OX9jyy.js} +6 -6
- package/dist/markdown-C3OX9jyy.js.map +1 -0
- package/dist/{spread-C8T12Nfh.js → spread-BT07rCJw.js} +7 -7
- package/dist/spread-BT07rCJw.js.map +1 -0
- package/dist/{table-CNQijNNB.js → table-CRG9eOs9.js} +3 -3
- package/dist/table-CRG9eOs9.js.map +1 -0
- package/dist/types/widgets-v2/actions/download/csv-item.d.ts +3 -3
- package/dist/types/widgets-v2/actions/download/index.d.ts +1 -1
- package/dist/types/widgets-v2/actions/download/png-item.d.ts +2 -2
- package/dist/types/widgets-v2/actions/download/types.d.ts +12 -1
- package/dist/types/widgets-v2/actions/fullscreen/fullscreen.d.ts +20 -13
- package/dist/types/widgets-v2/actions/index.d.ts +1 -1
- package/dist/types/widgets-v2/bar/download.d.ts +3 -3
- package/dist/types/widgets-v2/category/category-ui.d.ts +9 -1
- package/dist/types/widgets-v2/category/download.d.ts +3 -3
- package/dist/types/widgets-v2/echart/style.d.ts +1 -0
- package/dist/types/widgets-v2/formula/download.d.ts +3 -3
- package/dist/types/widgets-v2/histogram/download.d.ts +3 -3
- package/dist/types/widgets-v2/index.d.ts +1 -1
- package/dist/types/widgets-v2/markdown/download.d.ts +3 -3
- package/dist/types/widgets-v2/pie/download.d.ts +3 -3
- package/dist/types/widgets-v2/scatterplot/download.d.ts +3 -3
- package/dist/types/widgets-v2/spread/download.d.ts +3 -3
- package/dist/types/widgets-v2/table/download.d.ts +3 -3
- package/dist/types/widgets-v2/timeseries/download.d.ts +3 -3
- package/dist/types/widgets-v2/toolbox/toolbox.d.ts +1 -1
- package/dist/widgets-v2/actions.js +2 -2
- package/dist/widgets-v2/bar.js +7 -7
- package/dist/widgets-v2/bar.js.map +1 -1
- package/dist/widgets-v2/category.js +1 -1
- package/dist/widgets-v2/echart.js +1 -1
- package/dist/widgets-v2/formula.js +1 -1
- package/dist/widgets-v2/histogram.js +10 -10
- package/dist/widgets-v2/histogram.js.map +1 -1
- package/dist/widgets-v2/markdown.js +1 -1
- package/dist/widgets-v2/pie.js +10 -10
- package/dist/widgets-v2/pie.js.map +1 -1
- package/dist/widgets-v2/scatterplot.js +9 -9
- package/dist/widgets-v2/scatterplot.js.map +1 -1
- package/dist/widgets-v2/spread.js +1 -1
- package/dist/widgets-v2/table.js +1 -1
- package/dist/widgets-v2/timeseries.js +12 -12
- package/dist/widgets-v2/timeseries.js.map +1 -1
- package/dist/widgets-v2.js +274 -333
- package/dist/widgets-v2.js.map +1 -1
- package/package.json +3 -3
- package/src/widgets-v2/actions/download/csv-item.test.tsx +3 -3
- package/src/widgets-v2/actions/download/csv-item.tsx +6 -6
- package/src/widgets-v2/actions/download/download.tsx +5 -3
- package/src/widgets-v2/actions/download/index.ts +1 -1
- package/src/widgets-v2/actions/download/png-item.test.tsx +5 -3
- package/src/widgets-v2/actions/download/png-item.tsx +4 -4
- package/src/widgets-v2/actions/download/types.ts +15 -1
- package/src/widgets-v2/actions/fullscreen/fullscreen-store.test.tsx +155 -0
- package/src/widgets-v2/actions/fullscreen/fullscreen.test.tsx +39 -41
- package/src/widgets-v2/actions/fullscreen/fullscreen.tsx +211 -96
- package/src/widgets-v2/actions/index.ts +1 -0
- package/src/widgets-v2/actions/searcher/searcher.tsx +17 -2
- package/src/widgets-v2/bar/download.test.tsx +5 -3
- package/src/widgets-v2/bar/download.tsx +5 -4
- package/src/widgets-v2/category/category-ui.tsx +20 -9
- package/src/widgets-v2/category/category.tsx +37 -2
- package/src/widgets-v2/category/download.test.ts +4 -2
- package/src/widgets-v2/category/download.ts +5 -4
- package/src/widgets-v2/echart/style.ts +6 -0
- package/src/widgets-v2/formula/download.test.tsx +3 -1
- package/src/widgets-v2/formula/download.tsx +5 -4
- package/src/widgets-v2/histogram/download.test.ts +6 -4
- package/src/widgets-v2/histogram/download.ts +5 -4
- package/src/widgets-v2/index.ts +1 -0
- package/src/widgets-v2/markdown/download.test.ts +2 -2
- package/src/widgets-v2/markdown/download.tsx +5 -4
- package/src/widgets-v2/pie/download.test.ts +7 -3
- package/src/widgets-v2/pie/download.ts +5 -4
- package/src/widgets-v2/scatterplot/download.test.ts +4 -2
- package/src/widgets-v2/scatterplot/download.ts +5 -4
- package/src/widgets-v2/spread/download.test.ts +3 -1
- package/src/widgets-v2/spread/download.ts +5 -4
- package/src/widgets-v2/table/download.test.ts +5 -3
- package/src/widgets-v2/table/download.ts +4 -3
- package/src/widgets-v2/timeseries/download.test.ts +6 -4
- package/src/widgets-v2/timeseries/download.ts +5 -4
- package/src/widgets-v2/toolbox/toolbox.tsx +1 -1
- package/dist/actions-iN1jwyxA.js +0 -1024
- package/dist/actions-iN1jwyxA.js.map +0 -1
- package/dist/category-DZt6yiST.js +0 -826
- package/dist/category-DZt6yiST.js.map +0 -1
- package/dist/download-C7he8mSh.js.map +0 -1
- package/dist/echart-BnJYXH7H.js.map +0 -1
- package/dist/formula-Cqj84ZGX.js.map +0 -1
- package/dist/markdown-CV_KP-at.js.map +0 -1
- package/dist/spread-C8T12Nfh.js.map +0 -1
- package/dist/table-CNQijNNB.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"echart-CgOQw9XB.js","names":["echarts","ECharts","EChartsOption","EdgeAlignment","alignMinLabel","alignMaxLabel","CENTERED","SAFETY_MARGIN_PX","decideEdgeAlignment","args","firstLabel","lastLabel","font","firstTickX","lastTickX","width","halfFirst","format","getTextRect","halfLast","AxisLabel","formatter","value","fontSize","fontFamily","fontWeight","CategoryXAxis","type","axisLabel","SeriesLike","encode","x","datasetIndex","Cell","firstOf","T","Array","isArray","firstXAxis","option","axis","xAxis","undefined","hasDataZoom","dz","dataZoom","length","cellToText","fmt","String","resolveEdgeLabels","count","series0","series","encodeX","allDatasets","dataset","source","rows","Record","size","family","weight","clampEdgeLabels","chart","prev","next","computeAlignment","setOption","lazyUpdate","labels","convertToPixel","xAxisIndex","getWidth","Number","isFinite","ResizeCallback","callbacks","Map","Element","observer","ResizeObserver","getObserver","entries","entry","callback","get","target","NOOP_CLEANUP","undefined","observeResize","element","ro","set","observe","delete","unobserve","size","disconnect","__resetSharedResizeObserver","clear","SxProps","Theme","styles","root","width","flex","minHeight","isolation","Record","useEffect","useEffectEvent","useRef","Box","SxProps","Theme","echarts","clampEdgeLabels","CENTERED","EdgeAlignment","observeResize","styles","DEFAULT_INIT_OPTS","renderer","EChartsInitOpts","EchartsEventHandler","event","EchartUIProps","option","EChartsOption","replaceMerge","onEvents","Record","init","onInstance","chart","ECharts","className","sx","EchartUI","t0","$","_c","containerRef","chartRef","seriesFingerprintRef","datasetFingerprintRef","optionRef","edgeAlignRef","t1","notifyInstance","t2","current","chart_0","onFinished","on","onLegendSelectChanged","params","selected","names","Object","keys","length","every","name","dispatchAction","type","off","dispose","t3","t4","t5","seriesFp","computeSeriesFingerprint","datasetFp","computeDatasetFingerprint","augmented","Set","add","setOption","notMerge","lazyUpdate","size","Array","from","undefined","t6","t7","Symbol","for","node","resize","t8","t9","chart_1","handler","entries","event_0","handler_0","t10","root","t11","series","isArray","map","s","String","o","datasetIndex","stack","JSON","stringify","encode","join","dataset","useCallback","useMemo","SxProps","Theme","echarts","applyTransforms","setEchartInstance","useWidgetId","useWidgetShallow","Transform","EchartUI","EchartsEventHandler","DEFAULT_REPLACE_MERGE","OptionFactoryContext","formatter","value","labelFormatter","OptionFactory","option","EChartsOption","data","ctx","EchartProps","optionFactory","onEvents","Record","init","EChartsInitOpts","className","sx","EchartSlice","configTransforms","echartSelector","s","Echart","t0","$","_c","id","slice","t1","chart","onInstance","sliceData","sliceFormatter","sliceLabelFormatter","t2","undefined","structural","t3","transformed","t4","keys","Set","xf","enabled","replaceMergeKeys","length","k","add","Array","from","sort","replaceMerge","t5","t6","useCallback","useMemo","useRef","CallbackDataParams","EchartsEventHandler","SelectionKey","UseChartSelectionOptions","selection","K","onSelectionChange","next","keyFromClick","params","keysFromBrush","selected","seriesIndex","dataIndex","ChartSelectionWiring","onEvents","Record","useChartSelection","t0","$","_c","t1","event","key","current","idx","indexOf","slice","handleClick","t2","Symbol","for","latestBrushedRef","t3","event_0","params_0","batch","handleBrushSelected","t4","handleBrushEnd","t5","click","brushSelected","brushEnd","wiringSelection","length","t6"],"sources":["../src/widgets-v2/echart/edge-label-clamp.ts","../src/widgets-v2/echart/shared-resize-observer.ts","../src/widgets-v2/echart/style.ts","../src/widgets-v2/echart/echart-ui.tsx","../src/widgets-v2/echart/echart.tsx","../src/widgets-v2/echart/use-chart-selection.ts"],"sourcesContent":["import * as echarts from 'echarts'\nimport type { ECharts, EChartsOption } from 'echarts'\n\n/**\n * Render-time clamp that stops the first/last **category x-axis** labels from\n * clipping at the chart edges — *only when they actually overflow*.\n *\n * ECharts centers each category label on its tick; the first/last ticks sit at\n * the plot boundary, so a wide edge label spills past the chart and is cut off.\n * `grid.containLabel` does not contain this horizontal overflow and the v6\n * `outerBounds` shrink is unreliable, so we measure at render time and anchor\n * the overflowing edge label inward (`alignMinLabel: 'left'` /\n * `alignMaxLabel: 'right'`). Labels that fit stay centered.\n *\n * Lives in the generic bridge because the verdict needs the laid-out chart\n * (`convertToPixel`, `getWidth`); everything else is read from the `option`.\n * Auto-targets bar + histogram (category x-axis); pie's horizontal-bar fallback\n * (category *y*-axis), scatterplot (value) and timeseries (time) are skipped.\n */\n\nexport interface EdgeAlignment {\n alignMinLabel: 'left' | null\n alignMaxLabel: 'right' | null\n}\n\nexport const CENTERED: EdgeAlignment = {\n alignMinLabel: null,\n alignMaxLabel: null,\n}\n\n// Small cushion biasing toward anchoring when borderline: clipping is worse\n// than a hair of off-centering, and the measured width can differ slightly\n// from the final render (mainly when the web font isn't loaded yet at measure\n// time). Kept to 1px — a wider margin anchored labels that only just clear the\n// edge, and an anchored edge label can then be dropped by the axis\n// `hideOverlap`, leaving a gap. 1px guards measurement error without that.\nconst SAFETY_MARGIN_PX = 1\n\n/**\n * Pure overflow decision. Inputs are anchor-independent (tick centers and text\n * width don't depend on the label's current `text-anchor`), so feeding the\n * result back via `setOption` doesn't change them — the next pass yields the\n * same verdict, keeping the clamp loop-stable.\n */\nexport function decideEdgeAlignment(args: {\n firstLabel: string\n lastLabel: string\n font: string\n firstTickX: number\n lastTickX: number\n width: number\n}): EdgeAlignment {\n const halfFirst =\n echarts.format.getTextRect(args.firstLabel, args.font).width / 2\n const halfLast =\n echarts.format.getTextRect(args.lastLabel, args.font).width / 2\n return {\n alignMinLabel:\n halfFirst + SAFETY_MARGIN_PX > args.firstTickX ? 'left' : null,\n alignMaxLabel:\n halfLast + SAFETY_MARGIN_PX > args.width - args.lastTickX\n ? 'right'\n : null,\n }\n}\n\ninterface AxisLabel {\n formatter?: (value: string | number) => string | number\n fontSize?: number | string\n fontFamily?: string\n fontWeight?: number | string\n}\n\ninterface CategoryXAxis {\n type?: string\n axisLabel?: AxisLabel\n}\n\ninterface SeriesLike {\n encode?: { x?: string | number }\n datasetIndex?: number\n}\n\ntype Cell = string | number | null | undefined\n\nfunction firstOf<T>(value: T | T[] | undefined): T | undefined {\n if (Array.isArray(value)) return value[0]\n return value\n}\n\nfunction firstXAxis(option: EChartsOption): CategoryXAxis | undefined {\n const axis = firstOf(\n option.xAxis as CategoryXAxis | CategoryXAxis[] | undefined,\n )\n return axis && typeof axis === 'object' ? axis : undefined\n}\n\nfunction hasDataZoom(option: EChartsOption): boolean {\n const dz = option.dataZoom\n return Array.isArray(dz) ? dz.length > 0 : dz != null\n}\n\nfunction cellToText(value: Cell, fmt: AxisLabel['formatter']): string {\n if (typeof fmt === 'function') return String(fmt(value ?? ''))\n return value == null ? '' : String(value)\n}\n\n/**\n * Extracts the displayed first/last category strings and the label font from\n * the option, reading categories generically via `series[0].encode.x` into the\n * referenced dataset (`'name'` for bar, `0` for histogram). Returns `null` when\n * the option isn't a measurable category x-axis (fewer than 2 categories, no\n * dataset, etc.).\n */\nexport function resolveEdgeLabels(option: EChartsOption): {\n firstLabel: string\n lastLabel: string\n font: string\n count: number\n} | null {\n const xAxis = firstXAxis(option)\n if (!xAxis) return null\n if (xAxis.type !== 'category') return null\n\n const series0 = firstOf(\n option.series as SeriesLike | SeriesLike[] | undefined,\n )\n const encodeX = series0?.encode?.x\n if (encodeX == null) return null\n\n const datasetIndex = series0?.datasetIndex ?? 0\n const allDatasets = option.dataset as\n | { source?: unknown }\n | { source?: unknown }[]\n | undefined\n const dataset = Array.isArray(allDatasets)\n ? allDatasets[datasetIndex]\n : allDatasets\n const source = dataset?.source\n if (!Array.isArray(source) || source.length < 2) return null\n\n const rows = source as Record<string | number, Cell>[]\n const fmt = xAxis.axisLabel?.formatter\n const axisLabel = xAxis.axisLabel ?? {}\n const size =\n typeof axisLabel.fontSize === 'number'\n ? `${axisLabel.fontSize}px`\n : (axisLabel.fontSize ?? '12px')\n const family = axisLabel.fontFamily ?? 'sans-serif'\n const weight = axisLabel.fontWeight != null ? `${axisLabel.fontWeight} ` : ''\n\n return {\n firstLabel: cellToText(rows[0]?.[encodeX], fmt),\n lastLabel: cellToText(rows[rows.length - 1]?.[encodeX], fmt),\n font: `${weight}${size} ${family}`,\n count: source.length,\n }\n}\n\n/**\n * Measures the rendered chart and, when the edge labels would clip, applies\n * `alignMinLabel`/`alignMaxLabel` (or clears them) via an imperative merge\n * `setOption`. Returns the alignment now in effect so the caller can keep a\n * `prev` ref and skip redundant `setOption`s. Should be invoked from the\n * chart's `finished` event (layout is settled, so `convertToPixel` is valid).\n */\nexport function clampEdgeLabels(\n chart: ECharts,\n option: EChartsOption,\n prev: EdgeAlignment,\n): EdgeAlignment {\n const next = computeAlignment(chart, option)\n if (\n next.alignMinLabel === prev.alignMinLabel &&\n next.alignMaxLabel === prev.alignMaxLabel\n ) {\n return prev\n }\n chart.setOption({ xAxis: { axisLabel: { ...next } } } as EChartsOption, {\n lazyUpdate: true,\n })\n return next\n}\n\nfunction computeAlignment(\n chart: ECharts,\n option: EChartsOption,\n): EdgeAlignment {\n // Under dataZoom, convertToPixel on the absolute first/last index returns\n // off-plot pixels, so the overflow math is invalid — reset to centered.\n if (hasDataZoom(option)) return CENTERED\n\n const labels = resolveEdgeLabels(option)\n if (!labels) return CENTERED\n\n const firstTickX = chart.convertToPixel({ xAxisIndex: 0 }, 0)\n const lastTickX = chart.convertToPixel({ xAxisIndex: 0 }, labels.count - 1)\n const width = chart.getWidth()\n // Layout not measurable yet (defensive — `finished` normally fires after\n // layout). Fall back to centered; a later `finished` re-measures.\n if (\n typeof firstTickX !== 'number' ||\n typeof lastTickX !== 'number' ||\n !Number.isFinite(firstTickX) ||\n !Number.isFinite(lastTickX) ||\n !width\n ) {\n return CENTERED\n }\n\n return decideEdgeAlignment({\n firstLabel: labels.firstLabel,\n lastLabel: labels.lastLabel,\n font: labels.font,\n firstTickX,\n lastTickX,\n width,\n })\n}\n","type ResizeCallback = () => void\n\nconst callbacks = new Map<Element, ResizeCallback>()\nlet observer: ResizeObserver | null = null\n\n/**\n * Returns the singleton ResizeObserver, lazily constructing it on first use.\n * Returns `null` when `ResizeObserver` is not available in the global scope\n * (SSR, very old browsers, or tests that intentionally remove it).\n */\nfunction getObserver(): ResizeObserver | null {\n if (typeof ResizeObserver === 'undefined') return null\n observer ??= new ResizeObserver((entries) => {\n for (const entry of entries) {\n const callback = callbacks.get(entry.target)\n callback?.()\n }\n })\n return observer\n}\n\nconst NOOP_CLEANUP = (): void => undefined\n\nexport function observeResize(\n element: Element,\n callback: ResizeCallback,\n): () => void {\n const ro = getObserver()\n // Gracefully degrade when no ResizeObserver is available — consumers\n // still see one initial measure() pass via their own effect; we just\n // skip the subsequent resize-driven re-measures.\n if (!ro) return NOOP_CLEANUP\n callbacks.set(element, callback)\n ro.observe(element)\n return () => {\n callbacks.delete(element)\n if (observer) {\n observer.unobserve(element)\n // Disconnect the singleton once the last subscriber leaves so the\n // observer doesn't outlive its consumers in SSR teardown / micro-\n // frontend unmount scenarios. A subsequent observeResize() will\n // lazily re-create it via getObserver().\n if (callbacks.size === 0) {\n observer.disconnect()\n observer = null\n }\n }\n }\n}\n\n/** @internal — for tests only. */\nexport function __resetSharedResizeObserver(): void {\n if (observer) observer.disconnect()\n callbacks.clear()\n observer = null\n}\n","import type { SxProps, Theme } from '@mui/material'\n\nexport const styles = {\n root: {\n width: '100%',\n // `flex: 1` lets the chart fill a parent that has a definite height —\n // the fullscreen dialog. Inline it has none (Widget.Content is an\n // auto-height flex column), so flex-basis resolves to the content box,\n // which is empty until ECharts measures it: at `min-height: 0` the\n // container is 0px tall, ECharts draws nothing and the widget renders\n // blank. 304 is not a new magic number — it's the height `init.height`\n // used to pin, kept so cards look exactly as before. Override per widget\n // with `<Widget.Echart sx={{ minHeight }} />`.\n flex: 1,\n minHeight: 304,\n // ECharts puts its tooltip inside this box at `z-index: 9999999`. With\n // no stacking context of its own, that number competes page-wide and\n // beats MUI's modal layer — under `FullScreen.Slot` the card's chart\n // mirrors the dialog's tooltip (echarts.connect) and it painted over\n // the dialog. Isolating keeps the tooltip above its own chart only.\n isolation: 'isolate',\n },\n} satisfies Record<string, SxProps<Theme>>\n","import { useEffect, useEffectEvent, useRef } from 'react'\nimport { Box, type SxProps, type Theme } from '@mui/material'\nimport * as echarts from 'echarts'\nimport {\n clampEdgeLabels,\n CENTERED,\n type EdgeAlignment,\n} from './edge-label-clamp'\nimport { observeResize } from './shared-resize-observer'\nimport { styles } from './style'\n\n// No `height`: a numeric height here is stored in zrender's init opts, and\n// every later `resize()` resolves back to it — the chart would stay that tall\n// inside a fullscreen dialog. Height comes from the container instead\n// (`styles.root`'s `min-height` inline, `flex: 1` when the parent has one).\nexport const DEFAULT_INIT_OPTS = {\n renderer: 'svg',\n} satisfies echarts.EChartsInitOpts\n\nexport type EchartsEventHandler = (event: unknown) => void\n\nexport interface EchartUIProps {\n option: echarts.EChartsOption\n /**\n * Keys to merge as arrays (replace by index) instead of by id. The middleware\n * memoizes this content-stably, so identical sets don't re-trigger setOption.\n */\n replaceMerge?: readonly string[]\n /**\n * Opaque ECharts event passthrough — handlers fire untransformed.\n *\n * **Must be referentially stable** (memoize it with `useMemo` /\n * `useCallback`, or hoist to module scope). The binding effect depends on\n * the `onEvents` object identity; an inline `{ click: handler }` literal\n * recreates the object on every render and causes every listener to be\n * detached and re-attached each commit.\n */\n onEvents?: Record<string, EchartsEventHandler>\n /**\n * Init options forwarded to echarts.init. Captured at mount only — to change\n * `renderer` or `height` after mount, unmount and remount the chart.\n * Defaults: `{ renderer: 'svg' }` — height is container-driven, so prefer\n * `sx={{ minHeight }}` over pinning `height` here.\n */\n init?: echarts.EChartsInitOpts\n /**\n * Optional callback fired once after the ECharts instance is created\n * (`onInstance(chart)`) and once when it's about to be disposed\n * (`onInstance(null)`). Used by `Widget.Echart` to publish the live\n * instance to the per-widget registry so other actions (e.g.\n * `ZoomToggle`'s disable handler) can reach it without DOM lookups.\n * No need to memoize — the bridge wraps it in `useEffectEvent` so an\n * unstable reference does not re-init the chart.\n */\n onInstance?: (chart: echarts.ECharts | null) => void\n className?: string\n sx?: SxProps<Theme>\n}\n\nexport function EchartUI({\n option,\n replaceMerge,\n onEvents,\n init,\n onInstance,\n className,\n sx,\n}: EchartUIProps) {\n const containerRef = useRef<HTMLDivElement>(null)\n const chartRef = useRef<echarts.ECharts | null>(null)\n\n // Structural fingerprint of the last applied series / dataset arrays.\n // Used to decide whether the next `setOption` should *replace* those\n // components (when their shape changed) or *merge* them (when only\n // styling-level fields differ — e.g. a new `itemStyle.color` callback\n // from a selection update). Replacing wipes ECharts' per-series runtime\n // state (hover, animation cache, brush areas), so we want to do it only\n // when the structure actually moved.\n const seriesFingerprintRef = useRef<string | null>(null)\n const datasetFingerprintRef = useRef<string | null>(null)\n\n // Latest applied option (read by the `finished` clamp listener, which is\n // bound once and must see the current option) + the edge-label alignment\n // currently applied to the chart (so the clamp skips redundant setOptions).\n const optionRef = useRef<echarts.EChartsOption>(option)\n const edgeAlignRef = useRef<EdgeAlignment>(CENTERED)\n\n // Stable notify wrapper — always reads the latest `onInstance` prop\n // without forcing the init effect below to re-run when the parent\n // passes a fresh function reference. The init effect now only fires\n // when `init` actually changes (documented as mount-only anyway).\n const notifyInstance = useEffectEvent(\n (chart: echarts.ECharts | null): void => {\n onInstance?.(chart)\n },\n )\n\n // Init / dispose. `init` is captured once at mount.\n useEffect(() => {\n if (!containerRef.current) return undefined\n const chart = echarts.init(containerRef.current, null, {\n ...DEFAULT_INIT_OPTS,\n ...init,\n })\n chartRef.current = chart\n notifyInstance(chart)\n // Edge-label clamp: after each layout settles (option change OR resize both\n // end in a render → `finished`), measure the category x-axis edge labels\n // and anchor them inward only if they'd clip. `finished` (not rAF) so\n // `convertToPixel` sees the flushed `lazyUpdate` layout. Loop-safe: the\n // verdict is anchor-independent, so our own clamp setOption recomputes the\n // same result and the ref guard short-circuits.\n const onFinished = (): void => {\n edgeAlignRef.current = clampEdgeLabels(\n chart,\n optionRef.current,\n edgeAlignRef.current,\n )\n }\n chart.on('finished', onFinished)\n // Never let the legend end up with every item hidden — a user can click\n // series off one by one until the chart goes blank. `selected` on this\n // event is always the FULL name→boolean map (not just the clicked item),\n // so \"every value false\" reliably means \"nothing left visible\". Restore\n // all of them instead. `legendAllSelect` fires its own `legendselectall`\n // event, not `legendselectchanged`, so this can't re-trigger itself.\n // Always-on and independent of the consumer's `onEvents` — applies to\n // every ECharts widget in the library for free. A widget that disables\n // legend clicks entirely (e.g. Pie's `selectedMode: false`) never fires\n // `legendselectchanged`, so this is a no-op there.\n const onLegendSelectChanged = (params: unknown): void => {\n const { selected } = params as { selected?: Record<string, boolean> }\n if (!selected) return\n const names = Object.keys(selected)\n if (names.length > 0 && names.every((name) => !selected[name])) {\n chart.dispatchAction({ type: 'legendAllSelect' })\n }\n }\n chart.on('legendselectchanged', onLegendSelectChanged)\n return () => {\n chart.off('finished', onFinished)\n chart.off('legendselectchanged', onLegendSelectChanged)\n // Notify observers *before* disposal so any queued imperative\n // dispatches (e.g. ZoomToggle's `setOption` cleanup) see the\n // instance disappear before its DOM is torn down.\n notifyInstance(null)\n chart.dispose()\n chartRef.current = null\n }\n }, [init])\n\n // Apply option / replaceMerge changes via merge mode (no remount required).\n useEffect(() => {\n const seriesFp = computeSeriesFingerprint(option)\n const datasetFp = computeDatasetFingerprint(option)\n const augmented = new Set<string>(replaceMerge ?? [])\n if (seriesFp !== seriesFingerprintRef.current) augmented.add('series')\n if (datasetFp !== datasetFingerprintRef.current) augmented.add('dataset')\n seriesFingerprintRef.current = seriesFp\n datasetFingerprintRef.current = datasetFp\n // Expose the latest option to the `finished` clamp listener (bound once).\n optionRef.current = option\n chartRef.current?.setOption(option, {\n notMerge: false,\n lazyUpdate: true,\n replaceMerge: augmented.size > 0 ? Array.from(augmented) : undefined,\n })\n }, [option, replaceMerge])\n\n // Resize via shared singleton observer.\n useEffect(() => {\n const node = containerRef.current\n if (!node) return undefined\n return observeResize(node, () => {\n chartRef.current?.resize()\n })\n }, [])\n\n // Bind / unbind opaque event handlers.\n useEffect(() => {\n const chart = chartRef.current\n if (!chart || !onEvents) return undefined\n for (const [event, handler] of Object.entries(onEvents)) {\n chart.on(event, handler)\n }\n return () => {\n for (const [event, handler] of Object.entries(onEvents)) {\n chart.off(event, handler)\n }\n }\n }, [onEvents])\n\n return (\n <Box\n ref={containerRef}\n className={className}\n sx={{ ...styles.root, ...sx }}\n />\n )\n}\n\n/**\n * Cheap structural digest of the option's `series` array — covers the fields\n * that actually demand a `replaceMerge` (length, type, datasetIndex, name,\n * stack, encode). Excludes runtime-style fields like `itemStyle` (callbacks\n * have unstable identity but don't change structure).\n */\nfunction computeSeriesFingerprint(option: echarts.EChartsOption): string {\n const series = option.series\n if (!Array.isArray(series)) return series ? '1' : ''\n return series\n .map((s) => {\n if (s == null || typeof s !== 'object') return String(s)\n const o = s as Record<string, unknown>\n return [\n o.type,\n o.datasetIndex,\n o.name,\n o.stack,\n // `encode` is small; stringify is cheap and stable for plain objects.\n JSON.stringify(o.encode ?? null),\n ].join('|')\n })\n .join('||')\n}\n\n/**\n * Structural digest of the option's `dataset` array — count is the only\n * thing that needs `replaceMerge` here. Row-level changes are picked up by\n * ECharts' default merge.\n */\nfunction computeDatasetFingerprint(option: echarts.EChartsOption): string {\n const dataset = option.dataset\n if (!Array.isArray(dataset)) return dataset ? '1' : ''\n return String(dataset.length)\n}\n","import { useCallback, useMemo } from 'react'\nimport type { SxProps, Theme } from '@mui/material'\nimport type * as echarts from 'echarts'\nimport {\n applyTransforms,\n setEchartInstance,\n useWidgetId,\n useWidgetShallow,\n type Transform,\n} from '../stores'\nimport { EchartUI, type EchartsEventHandler } from './echart-ui'\n\n/**\n * Default ECharts `replaceMerge` keys for every widget. `dataZoom` and\n * `brush` are omitted so ZoomToggle / BrushToggle's user-driven runtime\n * state (slider range, brushed areas in `multiple` mode) survives unrelated\n * re-renders. `series` and `dataset` are also omitted: EchartUI fingerprints\n * them per-render and adds them to `replaceMerge` only when their shape\n * actually changes, keeping ECharts' per-series runtime state alive when\n * only callback-style fields differ.\n *\n * Lives in this module (not the generic store) because it's an ECharts\n * concept. Module-private — callers should not need it.\n */\nconst DEFAULT_REPLACE_MERGE: readonly string[] = ['toolbox']\n\n/**\n * Reactive context passed to every {@link OptionFactory} call so the\n * factory can rebuild render-time pieces (axis label / tooltip formatters)\n * from the live store. Drives RelativeData / consumer-formatter changes\n * through to the chart without rebuilding the structural option.\n */\nexport interface OptionFactoryContext {\n formatter?: (value: number) => string\n labelFormatter?: (value: string | number) => string | number\n}\n\n/**\n * The per-widget option factory — a single callable that owns BOTH phases\n * of option construction:\n *\n * - **Structural phase** — when `option == null`, return the theme-aware\n * structural option (tooltip / legend / color palette / series\n * template, optionally merged with a consumer-supplied `optionsOverride`).\n * No data is read. `<Widget.Echart>` calls the factory with\n * `(undefined, undefined)` synchronously during render to derive the\n * structural base; `configTransforms` (Stack/Zoom/Brush) then mutate it\n * in the same render pass.\n * - **Merge phase** — when `option` is defined, fuse `data` into the\n * post-configTransforms option at fusion time. `<Widget.Echart>` calls\n * the factory with `(transformed, data, ctx)` on every render.\n *\n * The two phases share a closure (the factory creator captures `theme`,\n * `formatter`, `labelFormatter`, `seriesNames`, `selection`, `optionsOverride`,\n * …), so structural and merge agree on the same widget configuration.\n *\n * The third arg `ctx` carries the **live** store-side formatters at the\n * call site — distinct from the closure-time formatters because actions\n * like RelativeData can install a percent formatter on the store after\n * the factory was constructed. The merge phase reads from `ctx`; the\n * structural phase typically uses the closure-time values.\n */\nexport type OptionFactory = (\n option: echarts.EChartsOption | undefined,\n data: unknown,\n ctx?: OptionFactoryContext,\n) => echarts.EChartsOption\n\nexport interface EchartProps {\n /**\n * The per-widget {@link OptionFactory}. Required — `<Widget.Echart>`\n * derives the structural option from it (so configTransforms have a base\n * to mutate) and fuses `state.data` into the post-pipeline option at\n * render time. Wrap the factory creator in `useMemo` so its identity is\n * stable across renders.\n */\n optionFactory: OptionFactory\n onEvents?: Record<string, EchartsEventHandler>\n init?: echarts.EChartsInitOpts\n className?: string\n /**\n * Styles for the chart container — this is where its height comes from.\n * `min-height` defaults to the card height (304px) and `flex: 1` lets the\n * chart fill a taller parent; override either here, e.g.\n * `sx={{ minHeight: 400 }}` for a taller card.\n */\n sx?: SxProps<Theme>\n}\n\ninterface EchartSlice {\n data: unknown\n configTransforms: readonly Transform[]\n formatter?: (value: number) => string\n labelFormatter?: (value: string | number) => string | number\n}\n\nconst echartSelector = (s: {\n data: unknown\n configTransforms: readonly Transform[]\n formatter?: (value: number) => string\n labelFormatter?: (value: string | number) => string | number\n}): EchartSlice => ({\n data: s.data,\n configTransforms: s.configTransforms,\n formatter: s.formatter,\n labelFormatter: s.labelFormatter,\n})\n\n/**\n * Stateful Echart bridge — owns the entire ECharts coupling. The whole\n * option pipeline lives here, not in the store:\n *\n * 1. **Structural** — `optionFactory(undefined, undefined)` produces the\n * theme-aware base. Memoized on the factory identity, so the consumer's\n * `useMemo` ID gates the rebuild.\n * 2. **Transformed** — `applyTransforms(structural, configTransforms)`\n * applies any registered configTransforms (Stack/Zoom/Brush) over the\n * structural base. Memoized on `[structural, configTransforms]`.\n * 3. **`replaceMerge`** — derived from the enabled configTransforms'\n * `replaceMergeKeys`, deduped and sorted, seeded with\n * {@link DEFAULT_REPLACE_MERGE}. Memoized on `[configTransforms]` so\n * ECharts sees a stable array reference across non-transform changes.\n * 4. **Merge** — `optionFactory(transformed, data, ctx)` fuses post-\n * pipeline data into the option. Reactive `ctx` carries the live store\n * formatters so RelativeData's percent formatter flows through without\n * a structural rebuild.\n *\n * The `<Widget.Provider>` doesn't know about the factory at all: it stays\n * a renderer-agnostic shell. The `ProviderProps` surface has no ECharts\n * coupling, so non-Echart widgets don't transitively import the type.\n */\nexport function Echart({\n optionFactory,\n onEvents,\n init,\n className,\n sx,\n}: EchartProps) {\n const id = useWidgetId()\n const slice = useWidgetShallow(id, echartSelector)\n\n // Publish the live ECharts instance to the per-id registry so actions\n // (e.g. `ZoomToggle`'s disable handler) can reach it imperatively. The\n // callback identity is stable across renders (only `id` is in deps), so\n // EchartUI's init effect doesn't see a fresh `onInstance` and re-init.\n const onInstance = useCallback(\n (chart: echarts.ECharts | null) => setEchartInstance(id, chart),\n [id],\n )\n\n // Destructure so React Compiler sees specific deps instead of inferring\n // the whole `slice` object. `useWidgetShallow` already shallow-compares\n // the slice, so per-field deps drive each memo exactly when its inputs\n // change.\n const {\n data: sliceData,\n configTransforms,\n formatter: sliceFormatter,\n labelFormatter: sliceLabelFormatter,\n } = slice\n\n const structural = useMemo(\n () => optionFactory(undefined, undefined),\n [optionFactory],\n )\n\n const transformed = useMemo(\n () =>\n applyTransforms(structural, configTransforms) as echarts.EChartsOption,\n [structural, configTransforms],\n )\n\n const replaceMerge = useMemo(() => {\n const keys = new Set<string>(DEFAULT_REPLACE_MERGE)\n for (const xf of configTransforms) {\n if (xf.enabled && xf.replaceMergeKeys?.length) {\n for (const k of xf.replaceMergeKeys) keys.add(k)\n }\n }\n return Array.from(keys).sort()\n }, [configTransforms])\n\n const option = useMemo(\n () =>\n optionFactory(transformed, sliceData, {\n formatter: sliceFormatter,\n labelFormatter: sliceLabelFormatter,\n }),\n [\n optionFactory,\n transformed,\n sliceData,\n sliceFormatter,\n sliceLabelFormatter,\n ],\n )\n\n return (\n <EchartUI\n option={option}\n replaceMerge={replaceMerge}\n onEvents={onEvents}\n init={init}\n onInstance={onInstance}\n className={className}\n sx={sx}\n />\n )\n}\n","import { useCallback, useMemo, useRef } from 'react'\nimport type { CallbackDataParams } from 'echarts/types/dist/shared'\nimport type { EchartsEventHandler } from './echart-ui'\n\nexport type SelectionKey = string | number\n\nexport interface UseChartSelectionOptions<K extends SelectionKey> {\n /**\n * Controlled selection. `undefined`/`null`/an explicit `[]` all mean \"no\n * selection interaction\" — every current merger already treats an empty\n * selection as \"nothing excluded,\" so this hook collapses all three to\n * `null` rather than promising per-merger `[]` semantics it doesn't\n * implement.\n */\n selection?: readonly K[]\n /** Receives the next selection. When omitted the wiring is a no-op. */\n onSelectionChange?: (next: readonly K[]) => void\n /**\n * Pull a selection key out of an ECharts `click` event. Return `null` to\n * skip (e.g. a click on empty plot area). For Bar/Pie/Timeseries this is\n * usually `(p) => p.name`; for Histogram/Scatterplot it's the dataIndex.\n */\n keyFromClick: (params: CallbackDataParams) => K | null\n /**\n * Map a `brushSelected` payload's `selected[*]` entries (each carrying a\n * `seriesIndex` + `dataIndex[]`) into the full set of selection keys for\n * the brushed area. Called once per brush event.\n */\n keysFromBrush: (\n selected: readonly { seriesIndex: number; dataIndex: number[] }[],\n ) => K[]\n}\n\nexport interface ChartSelectionWiring<K extends SelectionKey> {\n /**\n * Pass straight to `<Widget.Echart onEvents={…}>`. Wires `click` and\n * `brushSelected` so the user's interactions reach `onSelectionChange`.\n */\n onEvents: Record<string, EchartsEventHandler>\n /**\n * The current selection — `null` for \"no selection interaction\"\n * (`undefined`/`null`/an explicit `[]`), or a non-empty array meaning\n * \"render only these as fully opaque, dim the rest\".\n */\n selection: readonly K[] | null\n}\n\n/**\n * Translate ECharts' click + brush events into a consumer-owned selection\n * with the expected dashboard semantics:\n *\n * - **Click toggles** — clicking an item adds it to the selection if\n * absent, removes it if present.\n * - **Brush replaces** — finishing a brush stroke overwrites the selection\n * with whatever the brush covered (drag-to-empty clears).\n *\n * Wire the returned `onEvents` into `<Widget.Echart>` and feed\n * `wiring.selection` to the widget's option factory so the merger can dim\n * non-selected rows at fusion time.\n */\nexport function useChartSelection<K extends SelectionKey>({\n selection,\n onSelectionChange,\n keyFromClick,\n keysFromBrush,\n}: UseChartSelectionOptions<K>): ChartSelectionWiring<K> {\n const handleClick = useCallback(\n (event: unknown) => {\n if (!onSelectionChange) return\n const params = event as CallbackDataParams\n const key = keyFromClick(params)\n if (key == null) return\n const current = selection ?? []\n const idx = current.indexOf(key)\n const next =\n idx === -1\n ? [...current, key]\n : [...current.slice(0, idx), ...current.slice(idx + 1)]\n onSelectionChange(next)\n },\n [selection, onSelectionChange, keyFromClick],\n )\n\n // ECharts fires `brushSelected` on every pointer-move while the user is\n // drawing a brush, but we only want to push to `onSelectionChange` once\n // the gesture ends. Cache the latest `brushSelected` payload here, then\n // commit on `brushEnd`.\n const latestBrushedRef = useRef<\n readonly { seriesIndex: number; dataIndex: number[] }[]\n >([])\n\n const handleBrushSelected = useCallback((event: unknown) => {\n const params = event as {\n batch?: {\n selected?: { seriesIndex: number; dataIndex: number[] }[]\n }[]\n }\n latestBrushedRef.current = params.batch?.[0]?.selected ?? []\n }, [])\n\n const handleBrushEnd = useCallback(() => {\n if (!onSelectionChange) return\n onSelectionChange(keysFromBrush(latestBrushedRef.current))\n }, [onSelectionChange, keysFromBrush])\n\n const onEvents = useMemo<Record<string, EchartsEventHandler>>(\n () => ({\n click: handleClick,\n brushSelected: handleBrushSelected,\n brushEnd: handleBrushEnd,\n }),\n [handleClick, handleBrushSelected, handleBrushEnd],\n )\n\n const wiringSelection = useMemo(\n () => (selection && selection.length > 0 ? selection : null),\n [selection],\n )\n\n return { onEvents, selection: wiringSelection }\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { C as e, T as t } from "./stores-BVFMfgyo.js";
|
|
2
|
-
import { n, t as r } from "./download
|
|
2
|
+
import { n, t as r } from "./download--wRRnf19.js";
|
|
3
3
|
import { c as i } from "react/compiler-runtime";
|
|
4
4
|
import { Avatar as a, Box as o, Chip as s, Skeleton as c, Typography as l } from "@mui/material";
|
|
5
5
|
import { jsx as u, jsxs as d } from "react/jsx-runtime";
|
|
@@ -258,8 +258,8 @@ function A(e) {
|
|
|
258
258
|
backgroundColor: e.pngBackgroundColor
|
|
259
259
|
})), t.push(r({
|
|
260
260
|
filename: e.filename,
|
|
261
|
-
getRows: () => {
|
|
262
|
-
let
|
|
261
|
+
getRows: (t) => {
|
|
262
|
+
let n = e.getData(t), r = [[
|
|
263
263
|
"series",
|
|
264
264
|
"prefix",
|
|
265
265
|
"value",
|
|
@@ -267,7 +267,7 @@ function A(e) {
|
|
|
267
267
|
"note",
|
|
268
268
|
"delta"
|
|
269
269
|
]];
|
|
270
|
-
for (let e of
|
|
270
|
+
for (let e of n) r.push([
|
|
271
271
|
e.series?.name ?? "",
|
|
272
272
|
e.prefix ?? "",
|
|
273
273
|
e.value,
|
|
@@ -275,11 +275,11 @@ function A(e) {
|
|
|
275
275
|
e.note ?? "",
|
|
276
276
|
e.delta?.value ?? ""
|
|
277
277
|
]);
|
|
278
|
-
return
|
|
278
|
+
return r;
|
|
279
279
|
}
|
|
280
280
|
})), t;
|
|
281
281
|
}
|
|
282
282
|
//#endregion
|
|
283
283
|
export { S as a, v as c, m as d, C as i, _ as l, O as n, x as o, E as r, b as s, A as t, g as u };
|
|
284
284
|
|
|
285
|
-
//# sourceMappingURL=formula-
|
|
285
|
+
//# sourceMappingURL=formula-DRuMIVo8.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formula-DRuMIVo8.js","names":["Chip","ChipProps","DeltaSeverity","DeltaProps","value","label","severity","format","defaultPercentFormatter","Intl","NumberFormat","undefined","style","signDisplay","maximumFractionDigits","SEVERITY_TO_COLOR","Record","positive","negative","neutral","Delta","t0","$","_c","chipProps","resolvedSeverity","inferSeverity","t1","text","t2","t3","Symbol","for","fontWeight","t4","Typography","TypographyProps","ReactNode","NoteProps","children","Note","t0","$","_c","t1","Symbol","for","m","t2","Typography","TypographyProps","ReactNode","PrefixProps","children","Prefix","t0","$","_c","t1","Symbol","for","fontWeight","color","lineHeight","t2","Avatar","AvatarProps","Theme","SeriesProps","name","color","size","Series","t0","$","_c","t1","avatarProps","undefined","t2","charAt","toUpperCase","letter","t3","t4","t5","theme","palette","getContrastText","toCssColor","t6","width","height","fontSize","fontWeight","bgcolor","t7","value","includes","parts","split","cur","p","Record","Typography","TypographyProps","ReactNode","SuffixProps","children","Suffix","t0","$","_c","t1","Symbol","for","fontWeight","color","lineHeight","t2","Typography","TypographyProps","ReactNode","ValueProps","children","color","Value","t0","$","_c","t1","t2","fontWeight","lineHeight","t3","SxProps","Theme","styles","root","display","flexDirection","gap","alignItems","row","body","flex","minWidth","valueRow","delta","alignSelf","flexShrink","Record","Box","Ref","FormulaDataItem","Delta","Note","Prefix","Series","Suffix","Value","styles","FormulaUIProps","items","formatter","value","ref","HTMLDivElement","FormulaUI","t0","$","_c","t1","t2","item","i","series","name","prefix","suffix","row","color","body","valueRow","String","note","delta","label","severity","map","root","useWidgetId","useWidgetShallow","FormulaUI","FormulaWidgetData","FormulaSlice","data","formatter","value","EMPTY_DATA","Object","freeze","formulaSelector","s","Formula","$","_c","id","slice","t0","Box","Skeleton","SxProps","Theme","styles","root","display","gap","alignItems","minHeight","py","block","width","height","Record","FormulaSkeletonProps","count","FormulaSkeleton","t0","$","_c","t1","undefined","t2","Array","from","length","map","_temp","_","i","buildCsvDownloadItem","buildPngDownloadItem","DownloadContext","DownloadItem","FormulaWidgetData","FormulaDownloadConfigArgs","filename","getData","ctx","getCaptureEl","HTMLElement","pngPixelRatio","pngBackgroundColor","createFormulaDownloadConfig","args","items","push","pixelRatio","backgroundColor","getRows","data","rows","d","series","name","prefix","value","suffix","note","delta"],"sources":["../src/widgets-v2/formula/delta.tsx","../src/widgets-v2/formula/note.tsx","../src/widgets-v2/formula/prefix.tsx","../src/widgets-v2/formula/series.tsx","../src/widgets-v2/formula/suffix.tsx","../src/widgets-v2/formula/value.tsx","../src/widgets-v2/formula/style.ts","../src/widgets-v2/formula/formula-ui.tsx","../src/widgets-v2/formula/formula.tsx","../src/widgets-v2/formula/skeleton.tsx","../src/widgets-v2/formula/download.tsx"],"sourcesContent":["import { Chip, type ChipProps } from '@mui/material'\nimport type { DeltaSeverity } from './types'\n\nexport interface DeltaProps {\n /** Numeric magnitude. Used for the default percent label and severity inference. */\n value: number\n /** Pre-formatted label override; skips the default percent formatter. */\n label?: string\n /**\n * Visual treatment. When omitted it's derived from the sign of `value`:\n * `>0 → 'positive'`, `<0 → 'negative'`, `=0 → 'neutral'`.\n */\n severity?: DeltaSeverity\n /** Override the default `Intl.NumberFormat({style:'percent'})` formatter. */\n format?: (value: number) => string\n ChipProps?: ChipProps\n}\n\nconst defaultPercentFormatter = new Intl.NumberFormat(undefined, {\n style: 'percent',\n signDisplay: 'always',\n maximumFractionDigits: 1,\n})\n\nconst SEVERITY_TO_COLOR: Record<DeltaSeverity, ChipProps['color']> = {\n positive: 'success',\n negative: 'error',\n neutral: 'default',\n}\n\n/**\n * Comparative delta rendered as a small filled chip. Colour is driven by\n * `severity` (or the sign of `value`); content is `label`, the result of\n * `format(value)`, or the default percent format.\n */\nexport function Delta({\n value,\n label,\n severity,\n format,\n ChipProps: chipProps,\n}: DeltaProps) {\n const resolvedSeverity = severity ?? inferSeverity(value)\n const text =\n label ?? (format ? format(value) : defaultPercentFormatter.format(value))\n return (\n <Chip\n size='small'\n color={SEVERITY_TO_COLOR[resolvedSeverity]}\n label={text}\n sx={{ fontWeight: 600 }}\n {...chipProps}\n />\n )\n}\n\nfunction inferSeverity(value: number): DeltaSeverity {\n if (value > 0) return 'positive'\n if (value < 0) return 'negative'\n return 'neutral'\n}\n","import { Typography, type TypographyProps } from '@mui/material'\nimport type { ReactNode } from 'react'\n\nexport interface NoteProps {\n children: ReactNode\n TypographyProps?: TypographyProps\n}\n\n/**\n * Small subdued caption rendered below a Formula value. Use for short\n * descriptive text (e.g. \"Last 7 days\", \"Excludes refunds\").\n */\nexport function Note({ children, TypographyProps }: NoteProps) {\n return (\n <Typography\n variant='caption'\n component='p'\n color='text.secondary'\n sx={{ m: 0 }}\n {...TypographyProps}\n >\n {children}\n </Typography>\n )\n}\n","import { Typography, type TypographyProps } from '@mui/material'\nimport type { ReactNode } from 'react'\n\nexport interface PrefixProps {\n children: ReactNode\n TypographyProps?: TypographyProps\n}\n\n/**\n * Prefix slot for a Formula KPI — large, bold, muted (`text.secondary`).\n * Composable building block for custom formula layouts; the canonical\n * {@link FormulaUI} renders one of these per item when `prefix` is set.\n */\nexport function Prefix({ children, TypographyProps }: PrefixProps) {\n return (\n <Typography\n variant='h5'\n component='span'\n sx={{ fontWeight: 600, color: 'text.secondary', lineHeight: 1 }}\n {...TypographyProps}\n >\n {children}\n </Typography>\n )\n}\n","import { Avatar, type AvatarProps, type Theme } from '@mui/material'\n\nexport interface SeriesProps {\n /** Used for the avatar's first-letter glyph and as accessible label. */\n name: string\n /** Avatar background colour (any MUI palette path or CSS colour). */\n color?: string\n /** Diameter in px. Default `24`. */\n size?: number\n AvatarProps?: AvatarProps\n}\n\n/**\n * Series indicator — circular avatar showing the first letter of `name`.\n * Background colour is `color` (consumer-supplied) or a neutral disabled\n * colour, with text colour computed for contrast against it.\n */\nexport function Series({\n name,\n color,\n size = 24,\n AvatarProps: avatarProps,\n}: SeriesProps) {\n const letter = name.charAt(0).toUpperCase()\n return (\n <Avatar\n aria-label={name}\n sx={{\n width: size,\n height: size,\n fontSize: size * 0.5,\n fontWeight: 600,\n bgcolor: color ?? 'action.disabledBackground',\n color: color\n ? (theme: Theme) =>\n theme.palette.getContrastText(toCssColor(theme, color))\n : 'text.primary',\n }}\n {...avatarProps}\n >\n {letter}\n </Avatar>\n )\n}\n\n/**\n * Resolve a palette path (e.g. `\"primary.main\"`) to a hex/rgb string so that\n * `getContrastText` — which doesn't accept dotted paths — produces a sensible\n * text colour. Non-palette strings (raw `#hex`, `rgb(...)`) pass through.\n */\nfunction toCssColor(theme: Theme, value: string): string {\n if (!value.includes('.')) return value\n const parts = value.split('.')\n let cur: unknown = theme.palette\n for (const p of parts) {\n if (\n cur &&\n typeof cur === 'object' &&\n p in (cur as Record<string, unknown>)\n ) {\n cur = (cur as Record<string, unknown>)[p]\n } else {\n return value\n }\n }\n return typeof cur === 'string' ? cur : value\n}\n","import { Typography, type TypographyProps } from '@mui/material'\nimport type { ReactNode } from 'react'\n\nexport interface SuffixProps {\n children: ReactNode\n TypographyProps?: TypographyProps\n}\n\n/**\n * Suffix slot for a Formula KPI — large, bold, muted (`text.secondary`).\n * Composable building block for custom formula layouts; the canonical\n * {@link FormulaUI} renders one of these per item when `suffix` is set.\n */\nexport function Suffix({ children, TypographyProps }: SuffixProps) {\n return (\n <Typography\n variant='h5'\n component='span'\n sx={{ fontWeight: 600, color: 'text.secondary', lineHeight: 1 }}\n {...TypographyProps}\n >\n {children}\n </Typography>\n )\n}\n","import { Typography, type TypographyProps } from '@mui/material'\nimport type { ReactNode } from 'react'\n\nexport interface ValueProps {\n children: ReactNode\n /** Override the default `text.primary` color — useful for sparkline tints. */\n color?: string\n TypographyProps?: TypographyProps\n}\n\n/**\n * Value slot for a Formula KPI — large, bold, primary text color. Composable\n * building block for custom formula layouts; the canonical {@link FormulaUI}\n * renders one of these per item.\n */\nexport function Value({ children, color, TypographyProps }: ValueProps) {\n return (\n <Typography\n variant='h5'\n component='span'\n sx={{\n fontWeight: 600,\n color: color ?? 'text.primary',\n lineHeight: 1,\n }}\n {...TypographyProps}\n >\n {children}\n </Typography>\n )\n}\n","import type { SxProps, Theme } from '@mui/material'\n\nexport const styles = {\n root: {\n display: 'flex',\n flexDirection: 'column',\n gap: 2,\n alignItems: 'stretch',\n },\n row: {\n display: 'flex',\n alignItems: 'flex-start',\n gap: 1.5,\n },\n body: {\n flex: 1,\n minWidth: 0,\n display: 'flex',\n flexDirection: 'column',\n gap: 0.25,\n },\n valueRow: {\n display: 'inline-flex',\n alignItems: 'baseline',\n gap: 0.25,\n },\n delta: {\n alignSelf: 'center',\n flexShrink: 0,\n },\n} satisfies Record<string, SxProps<Theme>>\n","import { Box } from '@mui/material'\nimport type { Ref } from 'react'\nimport type { FormulaDataItem } from './types'\nimport { Delta } from './delta'\nimport { Note } from './note'\nimport { Prefix } from './prefix'\nimport { Series } from './series'\nimport { Suffix } from './suffix'\nimport { Value } from './value'\nimport { styles } from './style'\n\nexport interface FormulaUIProps {\n items: readonly FormulaDataItem[]\n /** Number formatter — applied to each item's `value`. */\n formatter?: (value: number) => string\n /** Forwarded to the root `<Box>` so consumers can capture the DOM (PNG export). */\n ref?: Ref<HTMLDivElement>\n}\n\n/**\n * Pure presentational component for the Formula widget. Each item renders as\n * a row containing (in order): optional `Series` avatar, a body with\n * `[prefix] value [suffix]` plus optional `Note`, and an optional `Delta`\n * chip pushed to the right edge.\n *\n * For fully custom layouts, compose {@link Series}, {@link Prefix},\n * {@link Value}, {@link Suffix}, {@link Note}, and {@link Delta} directly\n * instead of passing `items`.\n */\nexport function FormulaUI({ items, formatter, ref }: FormulaUIProps) {\n return (\n <Box ref={ref} sx={styles.root}>\n {items.map((item, i) => (\n // Series name is the closest stable id; fall back to the literal\n // value (numeric KPIs rarely repeat with the same prefix/suffix).\n <Box\n key={`formula-${item.series?.name ?? `${item.prefix ?? ''}${item.value}${item.suffix ?? ''}`}-${i}`}\n sx={styles.row}\n >\n {item.series ? (\n <Series name={item.series.name} color={item.series.color} />\n ) : null}\n <Box sx={styles.body}>\n <Box sx={styles.valueRow}>\n {item.prefix ? <Prefix>{item.prefix}</Prefix> : null}\n <Value color={item.color}>\n {formatter ? formatter(item.value) : String(item.value)}\n </Value>\n {item.suffix ? <Suffix>{item.suffix}</Suffix> : null}\n </Box>\n {item.note ? <Note>{item.note}</Note> : null}\n </Box>\n {item.delta ? (\n <Box sx={styles.delta}>\n <Delta\n value={item.delta.value}\n label={item.delta.label}\n severity={item.delta.severity}\n />\n </Box>\n ) : null}\n </Box>\n ))}\n </Box>\n )\n}\n","import { useWidgetId, useWidgetShallow } from '../stores'\nimport { FormulaUI } from './formula-ui'\nimport type { FormulaWidgetData } from './types'\n\ninterface FormulaSlice {\n data: FormulaWidgetData\n formatter?: (value: number) => string\n}\n\n// Stable empty-data sentinel — keeps the slice's `data` reference stable\n// when the underlying store value is null/undefined so the shallow-equality\n// gate in `useWidgetShallow` doesn't re-render every commit.\nconst EMPTY_DATA: FormulaWidgetData = Object.freeze([]) as FormulaWidgetData\n\nconst formulaSelector = (s: {\n data: unknown\n formatter?: (value: number) => string\n}): FormulaSlice => ({\n data: (s.data ?? EMPTY_DATA) as FormulaWidgetData,\n formatter: s.formatter,\n})\n\n/**\n * Stateful Formula bridge — reads `data` (post-pipeline) and `formatter` from\n * the per-widget store and forwards them to the pure {@link FormulaUI}. Sits\n * inside `<Widget.Provider>`. Demonstrates that the composition shell\n * (Provider, Wrapper, State) doesn't care whether the rendered child is\n * ECharts (Bar) or a custom DOM tree (Formula).\n */\nexport function Formula() {\n const id = useWidgetId()\n const slice = useWidgetShallow(id, formulaSelector)\n return <FormulaUI items={slice.data} formatter={slice.formatter} />\n}\n","import { Box, Skeleton } from '@mui/material'\nimport type { SxProps, Theme } from '@mui/material'\n\nconst styles = {\n root: {\n display: 'flex',\n gap: 3,\n alignItems: 'baseline',\n minHeight: 64,\n py: 1,\n },\n block: { width: 120, height: 36 },\n} satisfies Record<string, SxProps<Theme>>\n\nexport interface FormulaSkeletonProps {\n count?: number\n}\n\nexport function FormulaSkeleton({ count = 1 }: FormulaSkeletonProps) {\n return (\n <Box sx={styles.root}>\n {Array.from({ length: count }).map((_, i) => (\n <Skeleton key={`row-${i}`} variant='rectangular' sx={styles.block} />\n ))}\n </Box>\n )\n}\n","import {\n buildCsvDownloadItem,\n buildPngDownloadItem,\n type DownloadContext,\n type DownloadItem,\n} from '../actions/download'\nimport type { FormulaWidgetData } from './types'\n\nexport interface FormulaDownloadConfigArgs {\n filename: string\n getData: (ctx: DownloadContext) => FormulaWidgetData\n /**\n * Optional getter for the widget's capture element (registered by\n * `Widget.State`). When provided, a PNG item is prepended.\n */\n getCaptureEl?: (ctx: DownloadContext) => HTMLElement | null\n pngPixelRatio?: number\n pngBackgroundColor?: string | null\n}\n\n/**\n * Builds download items for the Formula widget. Always includes a CSV item\n * with one row per KPI (`prefix`, `value`, `suffix`, `note`, `delta`).\n * When `getCaptureEl` is supplied, prepends a PNG item that rasterises the\n * captured element via `html2canvas`.\n */\nexport function createFormulaDownloadConfig(\n args: FormulaDownloadConfigArgs,\n): DownloadItem[] {\n const items: DownloadItem[] = []\n if (args.getCaptureEl) {\n items.push(\n buildPngDownloadItem({\n filename: args.filename,\n getCaptureEl: args.getCaptureEl,\n pixelRatio: args.pngPixelRatio,\n backgroundColor: args.pngBackgroundColor,\n }),\n )\n }\n items.push(\n buildCsvDownloadItem({\n filename: args.filename,\n getRows: (ctx) => {\n const data = args.getData(ctx)\n const rows: unknown[][] = [\n ['series', 'prefix', 'value', 'suffix', 'note', 'delta'],\n ]\n for (const d of data) {\n rows.push([\n d.series?.name ?? '',\n d.prefix ?? '',\n d.value,\n d.suffix ?? '',\n d.note ?? '',\n d.delta?.value ?? '',\n ])\n }\n return rows\n },\n }),\n )\n return items\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { S as e, T as t } from "./stores-BVFMfgyo.js";
|
|
2
2
|
import { t as n } from "./markdown-content-BzKoX3eu.js";
|
|
3
|
-
import { a as r, n as i, r as a } from "./download
|
|
3
|
+
import { a as r, n as i, r as a } from "./download--wRRnf19.js";
|
|
4
4
|
import { c as o } from "react/compiler-runtime";
|
|
5
5
|
import { Box as s, Skeleton as c, Typography as l } from "@mui/material";
|
|
6
6
|
import { jsx as u } from "react/jsx-runtime";
|
|
@@ -149,12 +149,12 @@ function y(e) {
|
|
|
149
149
|
id: a.markdown,
|
|
150
150
|
label: "Markdown",
|
|
151
151
|
icon: /* @__PURE__ */ u(r, { fontSize: "small" }),
|
|
152
|
-
resolve: () => {
|
|
153
|
-
let
|
|
152
|
+
resolve: (t) => {
|
|
153
|
+
let n = e.getData(t), r = new Blob([n.content ?? ""], { type: "text/markdown;charset=utf-8;" }), i = URL.createObjectURL(r);
|
|
154
154
|
return Promise.resolve({
|
|
155
|
-
url:
|
|
155
|
+
url: i,
|
|
156
156
|
filename: `${e.filename}.md`,
|
|
157
|
-
revoke: () => URL.revokeObjectURL(
|
|
157
|
+
revoke: () => URL.revokeObjectURL(i)
|
|
158
158
|
});
|
|
159
159
|
}
|
|
160
160
|
}), t;
|
|
@@ -162,4 +162,4 @@ function y(e) {
|
|
|
162
162
|
//#endregion
|
|
163
163
|
export { m as i, v as n, h as r, y as t };
|
|
164
164
|
|
|
165
|
-
//# sourceMappingURL=markdown-
|
|
165
|
+
//# sourceMappingURL=markdown-C3OX9jyy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-C3OX9jyy.js","names":["SxProps","Theme","styles","root","color","bgcolor","px","borderRadius","fontFamily","fontSize","p","overflowX","borderLeft","borderColor","pl","ml","fontStyle","my","border","borderTop","borderCollapse","width","py","textAlign","paragraph","heading","mt","mb","fontWeight","Record","Box","Typography","TypographyProps","Components","MarkdownContent","styles","MarkdownUIProps","content","components","h1","props","mdHeading","h2","h3","h4","h5","h6","p","children","paragraph","React","ReactNode","variant","heading","MarkdownUI","t0","$","_c","t1","root","useWidgetId","useWidget","MarkdownUI","MarkdownWidgetData","Markdown","$","_c","id","content","_temp","t0","s","data","Box","Skeleton","SxProps","Theme","styles","root","display","flexDirection","gap","py","line","width","height","const","MarkdownSkeletonProps","lines","MarkdownSkeleton","t0","$","_c","t1","undefined","t2","widths","Array","from","length","map","_","i","DOWNLOAD_ITEM_IDS","MarkdownIcon","buildPngDownloadItem","toCsvString","triggerLinkDownload","DownloadContext","DownloadItem","MarkdownWidgetData","createMarkdownDownloadConfig","args","filename","getData","ctx","getCaptureEl","HTMLElement","pngPixelRatio","pngBackgroundColor","items","push","pixelRatio","backgroundColor","id","markdown","label","icon","resolve","data","blob","Blob","content","type","url","URL","createObjectURL","Promise","revoke","revokeObjectURL"],"sources":["../src/widgets-v2/markdown/style.ts","../src/widgets-v2/markdown/markdown-ui.tsx","../src/widgets-v2/markdown/markdown.tsx","../src/widgets-v2/markdown/skeleton.tsx","../src/widgets-v2/markdown/download.tsx"],"sourcesContent":["import type { SxProps, Theme } from '@mui/material'\n\nexport const styles = {\n root: {\n color: 'text.primary',\n '& a': { color: 'primary.main' },\n '& code': {\n bgcolor: 'action.hover',\n px: 0.5,\n borderRadius: 0.5,\n fontFamily: 'monospace',\n fontSize: '0.875em',\n },\n '& pre': {\n bgcolor: 'action.hover',\n p: 1.5,\n borderRadius: 1,\n overflowX: 'auto',\n },\n '& blockquote': {\n borderLeft: '3px solid',\n borderColor: 'divider',\n pl: 1.5,\n ml: 0,\n color: 'text.secondary',\n fontStyle: 'italic',\n },\n '& ul, & ol': { pl: 3, my: 1 },\n '& li': { my: 0.25 },\n '& hr': {\n border: 'none',\n borderTop: '1px solid',\n borderColor: 'divider',\n my: 1.5,\n },\n '& table': { borderCollapse: 'collapse', width: '100%' },\n '& th, & td': {\n border: '1px solid',\n borderColor: 'divider',\n px: 1,\n py: 0.5,\n textAlign: 'left',\n },\n },\n paragraph: {\n my: 1,\n },\n heading: {\n mt: 2,\n mb: 1,\n fontWeight: 600,\n },\n} satisfies Record<string, SxProps<Theme>>\n","import { Box, Typography, type TypographyProps } from '@mui/material'\nimport type { Components } from 'react-markdown'\nimport { MarkdownContent } from './markdown-content'\nimport { styles } from './style'\n\nexport interface MarkdownUIProps {\n content: string\n}\n\n/** MUI-styled element mapping for `react-markdown`. */\nconst components: Components = {\n h1: (props) => mdHeading(props, 'h4'),\n h2: (props) => mdHeading(props, 'h5'),\n h3: (props) => mdHeading(props, 'h6'),\n h4: (props) => mdHeading(props, 'subtitle1'),\n h5: (props) => mdHeading(props, 'subtitle2'),\n h6: (props) => mdHeading(props, 'subtitle2'),\n p: ({ children }) => (\n <Typography variant='body2' component='p' sx={styles.paragraph}>\n {children}\n </Typography>\n ),\n}\n\nfunction mdHeading(\n props: { children?: React.ReactNode },\n variant: TypographyProps['variant'],\n) {\n return (\n <Typography variant={variant} component='div' sx={styles.heading}>\n {props.children}\n </Typography>\n )\n}\n\n/**\n * Pure presentational component for the Markdown widget. Delegates the\n * `react-markdown` engine to {@link MarkdownContent} and supplies a\n * document-style MUI element mapping (body2 paragraphs, real heading\n * typography). Opts INTO raw HTML and inline images — the Markdown widget is\n * the one slot in the library where authors can ship rich content. Caption\n * slots like `Note` keep the conservative defaults.\n */\nexport function MarkdownUI({ content }: MarkdownUIProps) {\n return (\n <Box sx={styles.root}>\n <MarkdownContent\n content={content}\n components={components}\n allowHtml\n allowImages\n />\n </Box>\n )\n}\n","import { useWidgetId, useWidget } from '../stores'\nimport { MarkdownUI } from './markdown-ui'\nimport type { MarkdownWidgetData } from './types'\n\n/**\n * Stateful Markdown bridge — reads `data.content` (post-pipeline) from the\n * per-widget store and forwards it to the pure {@link MarkdownUI}. Sits\n * inside `<Widget.Provider>`.\n */\nexport function Markdown() {\n const id = useWidgetId()\n const content = useWidget(id, (s) => {\n const data = s.data as MarkdownWidgetData | undefined\n return data?.content ?? ''\n })\n return <MarkdownUI content={content} />\n}\n","import { Box, Skeleton } from '@mui/material'\nimport type { SxProps, Theme } from '@mui/material'\n\nconst styles = {\n root: {\n display: 'flex',\n flexDirection: 'column',\n gap: 1,\n py: 1,\n },\n line: (width: string): SxProps<Theme> => ({ width, height: 18 }),\n} as const\n\nexport interface MarkdownSkeletonProps {\n lines?: number\n}\n\nexport function MarkdownSkeleton({ lines = 5 }: MarkdownSkeletonProps) {\n // Vary widths to mimic prose.\n const widths = ['100%', '95%', '90%', '85%', '70%']\n return (\n <Box sx={styles.root}>\n {Array.from({ length: lines }).map((_, i) => (\n <Skeleton\n key={`line-${i}`}\n variant='rectangular'\n sx={styles.line(widths[i % widths.length] ?? '85%')}\n />\n ))}\n </Box>\n )\n}\n","import {\n DOWNLOAD_ITEM_IDS,\n MarkdownIcon,\n buildPngDownloadItem,\n toCsvString,\n triggerLinkDownload,\n type DownloadContext,\n type DownloadItem,\n} from '../actions/download'\nimport type { MarkdownWidgetData } from './types'\n\n/**\n * Download menu items for the Markdown widget. Always includes a `.md`\n * item that saves the markdown source verbatim. When `getCaptureEl` is\n * supplied, prepends a PNG item that rasterises the captured element via\n * `html2canvas`.\n */\nexport function createMarkdownDownloadConfig(args: {\n filename: string\n getData: (ctx: DownloadContext) => MarkdownWidgetData\n getCaptureEl?: (ctx: DownloadContext) => HTMLElement | null\n pngPixelRatio?: number\n pngBackgroundColor?: string | null\n}): DownloadItem[] {\n const items: DownloadItem[] = []\n if (args.getCaptureEl) {\n items.push(\n buildPngDownloadItem({\n filename: args.filename,\n getCaptureEl: args.getCaptureEl,\n pixelRatio: args.pngPixelRatio,\n backgroundColor: args.pngBackgroundColor,\n }),\n )\n }\n items.push({\n id: DOWNLOAD_ITEM_IDS.markdown,\n label: 'Markdown',\n icon: <MarkdownIcon fontSize='small' />,\n resolve: (ctx) => {\n const data = args.getData(ctx)\n const blob = new Blob([data.content ?? ''], {\n type: 'text/markdown;charset=utf-8;',\n })\n const url = URL.createObjectURL(blob)\n return Promise.resolve({\n url,\n filename: `${args.filename}.md`,\n revoke: () => URL.revokeObjectURL(url),\n })\n },\n })\n return items\n}\n\n// Re-export pure helpers consumers may want when building a custom Download item.\nexport { toCsvString, triggerLinkDownload }\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { C as e, T as t } from "./stores-BVFMfgyo.js";
|
|
2
|
-
import { n, t as r } from "./download
|
|
3
|
-
import { a as i, c as a, l as o, o as s, s as c, u as l } from "./formula-
|
|
2
|
+
import { n, t as r } from "./download--wRRnf19.js";
|
|
3
|
+
import { a as i, c as a, l as o, o as s, s as c, u as l } from "./formula-DRuMIVo8.js";
|
|
4
4
|
import { c as u } from "react/compiler-runtime";
|
|
5
5
|
import { Box as d, Skeleton as f } from "@mui/material";
|
|
6
6
|
import { jsx as p, jsxs as m } from "react/jsx-runtime";
|
|
@@ -113,8 +113,8 @@ function w(e) {
|
|
|
113
113
|
backgroundColor: e.pngBackgroundColor
|
|
114
114
|
})), t.push(r({
|
|
115
115
|
filename: e.filename,
|
|
116
|
-
getRows: () => {
|
|
117
|
-
let
|
|
116
|
+
getRows: (t) => {
|
|
117
|
+
let n = e.getData(t), r = [[
|
|
118
118
|
"series",
|
|
119
119
|
"prefix",
|
|
120
120
|
"min",
|
|
@@ -122,7 +122,7 @@ function w(e) {
|
|
|
122
122
|
"suffix",
|
|
123
123
|
"note"
|
|
124
124
|
]];
|
|
125
|
-
for (let e of
|
|
125
|
+
for (let e of n) r.push([
|
|
126
126
|
e.series?.name ?? "",
|
|
127
127
|
e.prefix ?? "",
|
|
128
128
|
e.min,
|
|
@@ -130,7 +130,7 @@ function w(e) {
|
|
|
130
130
|
e.suffix ?? "",
|
|
131
131
|
e.note ?? ""
|
|
132
132
|
]);
|
|
133
|
-
return
|
|
133
|
+
return r;
|
|
134
134
|
}
|
|
135
135
|
})), t;
|
|
136
136
|
}
|
|
@@ -146,4 +146,4 @@ function T({ value: e, spread: t, variant: n = "percentage" }) {
|
|
|
146
146
|
//#endregion
|
|
147
147
|
export { g as a, b as i, w as n, h as o, S as r, T as t };
|
|
148
148
|
|
|
149
|
-
//# sourceMappingURL=spread-
|
|
149
|
+
//# sourceMappingURL=spread-BT07rCJw.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spread-BT07rCJw.js","names":["Value","Separator","$","_c","t0","Symbol","for","Box","Ref","Note","Prefix","Series","Suffix","Value","styles","Separator","SpreadDataItem","SpreadUIProps","items","formatter","value","ref","HTMLDivElement","SpreadUI","t0","$","_c","fmt","_temp","t1","t2","item","i","series","name","min","max","row","color","body","valueRow","prefix","suffix","note","map","root","n","String","useWidgetId","useWidgetShallow","SpreadUI","SpreadWidgetData","SpreadSlice","data","formatter","value","EMPTY_DATA","Object","freeze","spreadSelector","s","Spread","$","_c","id","slice","t0","Box","Skeleton","SxProps","Theme","styles","root","display","flexDirection","gap","py","row","alignItems","block","width","height","Record","SpreadSkeletonProps","count","SpreadSkeleton","t0","$","_c","t1","undefined","t2","Array","from","length","map","_temp","_","i","buildCsvDownloadItem","buildPngDownloadItem","DownloadContext","DownloadItem","SpreadWidgetData","createSpreadDownloadConfig","args","filename","getData","ctx","getCaptureEl","HTMLElement","pngPixelRatio","pngBackgroundColor","items","push","pixelRatio","backgroundColor","getRows","data","rows","item","series","name","prefix","min","max","suffix","note","SpreadVariant","GetSpreadBandOptions","value","spread","variant","getSpreadBand","min","max","offset","width","Math","abs"],"sources":["../src/widgets-v2/spread/separator.tsx","../src/widgets-v2/spread/spread-ui.tsx","../src/widgets-v2/spread/spread.tsx","../src/widgets-v2/spread/skeleton.tsx","../src/widgets-v2/spread/download.ts","../src/widgets-v2/spread/band.ts"],"sourcesContent":["import { Value } from '../formula'\n\n/**\n * Em-dash separator placed between a Spread row's `min` and `max` values.\n * Built from the Formula {@link Value} primitive so typography (h5/600,\n * baseline alignment) matches the numbers around it. Renders with\n * `text.secondary` so it visually recedes between the two bounds.\n */\nexport function Separator() {\n return <Value color='inherit'>-</Value>\n}\n","import { Box } from '@mui/material'\nimport type { Ref } from 'react'\nimport { Note, Prefix, Series, Suffix, Value } from '../formula'\nimport { styles } from '../formula/style'\nimport { Separator } from './separator'\nimport type { SpreadDataItem } from './types'\n\nexport interface SpreadUIProps {\n items: readonly SpreadDataItem[]\n /** Number formatter — applied to each item's `min` and `max`. */\n formatter?: (value: number) => string\n /** Forwarded to the root `<Box>` so consumers can capture the DOM (PNG export). */\n ref?: Ref<HTMLDivElement>\n}\n\n/**\n * Pure presentational component for the Spread widget. Each item renders as\n * a row containing (in order): optional `Series` avatar, a body with\n * `[prefix] min — max [suffix]` plus optional `Note`. Reuses the Formula\n * primitives ({@link Series}, {@link Prefix}, {@link Value}, {@link Suffix},\n * {@link Note}) and the Formula row styles so Spread and Formula stay\n * visually aligned when used together.\n */\nexport function SpreadUI({ items, formatter, ref }: SpreadUIProps) {\n const fmt = formatter ?? ((n: number) => String(n))\n return (\n <Box ref={ref} sx={styles.root}>\n {items.map((item, i) => (\n // Composite of series name + min/max bounds for stability across\n // reorders; falls back to the index when bounds happen to collide.\n <Box\n key={`spread-${item.series?.name ?? ''}-${item.min}-${item.max}-${i}`}\n sx={styles.row}\n >\n {item.series ? (\n <Series name={item.series.name} color={item.series.color} />\n ) : null}\n <Box sx={styles.body}>\n <Box sx={styles.valueRow}>\n {item.prefix ? <Prefix>{item.prefix}</Prefix> : null}\n <Value color={item.color}>{fmt(item.min)}</Value>\n <Separator />\n <Value color={item.color}>{fmt(item.max)}</Value>\n {item.suffix ? <Suffix>{item.suffix}</Suffix> : null}\n </Box>\n {item.note ? <Note>{item.note}</Note> : null}\n </Box>\n </Box>\n ))}\n </Box>\n )\n}\n","import { useWidgetId, useWidgetShallow } from '../stores'\nimport { SpreadUI } from './spread-ui'\nimport type { SpreadWidgetData } from './types'\n\ninterface SpreadSlice {\n data: SpreadWidgetData\n formatter?: (value: number) => string\n}\n\n// Stable empty-data sentinel — keeps the slice's `data` reference stable\n// when the underlying store value is null/undefined so the shallow-equality\n// gate in `useWidgetShallow` doesn't re-render every commit.\nconst EMPTY_DATA: SpreadWidgetData = Object.freeze([]) as SpreadWidgetData\n\nconst spreadSelector = (s: {\n data: unknown\n formatter?: (value: number) => string\n}): SpreadSlice => ({\n data: (s.data ?? EMPTY_DATA) as SpreadWidgetData,\n formatter: s.formatter,\n})\n\n/**\n * Stateful Spread bridge — reads `data` (post-pipeline) and `formatter` from\n * the per-widget store and forwards them to the pure {@link SpreadUI}.\n */\nexport function Spread() {\n const id = useWidgetId()\n const slice = useWidgetShallow(id, spreadSelector)\n return <SpreadUI items={slice.data} formatter={slice.formatter} />\n}\n","import { Box, Skeleton } from '@mui/material'\nimport type { SxProps, Theme } from '@mui/material'\n\nconst styles = {\n root: {\n display: 'flex',\n flexDirection: 'column',\n gap: 2,\n py: 1,\n },\n row: {\n display: 'flex',\n alignItems: 'center',\n gap: 1.5,\n },\n block: { width: 200, height: 32 },\n} satisfies Record<string, SxProps<Theme>>\n\nexport interface SpreadSkeletonProps {\n count?: number\n}\n\n/**\n * Loading placeholder for the Spread widget. Renders `count` rows, each\n * sized for the `min — max` pair so the layout doesn't jump once data\n * resolves. Mirrors the row-per-item structure of {@link SpreadUI}.\n */\nexport function SpreadSkeleton({ count = 1 }: SpreadSkeletonProps) {\n return (\n <Box sx={styles.root}>\n {Array.from({ length: count }).map((_, i) => (\n <Box key={`row-${i}`} sx={styles.row}>\n <Skeleton variant='rectangular' sx={styles.block} />\n </Box>\n ))}\n </Box>\n )\n}\n","import {\n buildCsvDownloadItem,\n buildPngDownloadItem,\n type DownloadContext,\n type DownloadItem,\n} from '../actions/download'\nimport type { SpreadWidgetData } from './types'\n\n/**\n * Download menu items for the Spread widget. Always includes a CSV item\n * with `series, prefix, min, max, suffix, note` columns (one row per\n * entry). When `getCaptureEl` is supplied, prepends a PNG item that\n * rasterises the captured element via `html2canvas`.\n */\nexport function createSpreadDownloadConfig(args: {\n filename: string\n getData: (ctx: DownloadContext) => SpreadWidgetData\n getCaptureEl?: (ctx: DownloadContext) => HTMLElement | null\n pngPixelRatio?: number\n pngBackgroundColor?: string | null\n}): DownloadItem[] {\n const items: DownloadItem[] = []\n if (args.getCaptureEl) {\n items.push(\n buildPngDownloadItem({\n filename: args.filename,\n getCaptureEl: args.getCaptureEl,\n pixelRatio: args.pngPixelRatio,\n backgroundColor: args.pngBackgroundColor,\n }),\n )\n }\n items.push(\n buildCsvDownloadItem({\n filename: args.filename,\n getRows: (ctx) => {\n const data = args.getData(ctx)\n const rows: unknown[][] = [\n ['series', 'prefix', 'min', 'max', 'suffix', 'note'],\n ]\n for (const item of data) {\n rows.push([\n item.series?.name ?? '',\n item.prefix ?? '',\n item.min,\n item.max,\n item.suffix ?? '',\n item.note ?? '',\n ])\n }\n return rows\n },\n }),\n )\n return items\n}\n","/**\n * How a `spread` amount is applied to a centre value.\n *\n * - `percentage` — `spread` is a whole-number percentage of the centre\n * value, so `5` means +/-5%.\n * - `absolute` — `spread` is a raw offset in the value's own units.\n */\nexport type SpreadVariant = 'percentage' | 'absolute'\n\nexport interface GetSpreadBandOptions {\n /** The centre value the band is drawn around. */\n value: number\n /** Half-width of the band, read according to `variant`. */\n spread: number\n /** Defaults to `percentage`. */\n variant?: SpreadVariant\n}\n\n/**\n * Derives the `min` / `max` band around a centre value, for feeding a\n * {@link SpreadDataItem} from a single aggregated number (a prediction, a\n * target) plus a tolerance — rather than from a real column range.\n *\n * `spread` is read as a percentage by default, which is what a tolerance\n * almost always is: an absolute offset is meaningless without knowing the\n * value's magnitude, and gets visually lost on large values (+/-5 on a\n * prediction of 204,113 renders as a range indistinguishable from a single\n * number).\n *\n * @example\n * getSpreadBand({ value: 1000, spread: 5 })\n * // -> { min: 950, max: 1050 }\n * getSpreadBand({ value: 1000, spread: 5, variant: 'absolute' })\n * // -> { min: 995, max: 1005 }\n */\nexport function getSpreadBand({\n value,\n spread,\n variant = 'percentage',\n}: GetSpreadBandOptions): { min: number; max: number } {\n const offset = variant === 'absolute' ? spread : (spread / 100) * value\n // Keep `min <= max`: a percentage of a negative centre value (or a negative\n // `spread`) yields a negative offset, which would invert the band.\n const width = Math.abs(offset)\n\n return { min: value - width, max: value + width }\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { C as e, S as t, T as n, p as r } from "./stores-BVFMfgyo.js";
|
|
2
|
-
import { d as i, n as a, t as o } from "./download
|
|
2
|
+
import { d as i, n as a, t as o } from "./download--wRRnf19.js";
|
|
3
3
|
import { c as ee } from "react/compiler-runtime";
|
|
4
4
|
import "react";
|
|
5
5
|
import { Box as s, Checkbox as c, IconButton as l, Skeleton as u, Table as d, TableBody as f, TableCell as p, TableContainer as m, TableHead as h, TablePagination as g, TableRow as _, TableSortLabel as v } from "@mui/material";
|
|
@@ -419,7 +419,7 @@ function V(e) {
|
|
|
419
419
|
backgroundColor: e.pngBackgroundColor
|
|
420
420
|
})), t.push(o({
|
|
421
421
|
filename: e.filename,
|
|
422
|
-
getCsv: () => L(e.getData(), e.columns)
|
|
422
|
+
getCsv: (t) => L(e.getData(t), e.columns)
|
|
423
423
|
})), t;
|
|
424
424
|
}
|
|
425
425
|
//#endregion
|
|
@@ -436,4 +436,4 @@ function oe(e, t, n = "id") {
|
|
|
436
436
|
//#endregion
|
|
437
437
|
export { M as a, F as c, j as d, O as f, B as i, N as l, D as m, V as n, I as o, k as p, ie as r, P as s, oe as t, L as u };
|
|
438
438
|
|
|
439
|
-
//# sourceMappingURL=table-
|
|
439
|
+
//# sourceMappingURL=table-CRG9eOs9.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"table-CRG9eOs9.js","names":["Box","SxProps","Theme","ReactNode","TableLabels","selectAll","selectRow","rowId","rowsPerPage","paginationOf","from","to","total","firstPage","previousPage","nextPage","lastPage","boldRange","fontWeight","color","DEFAULT_TABLE_LABELS","id","ReactNode","WidgetState","TableRow","Record","id","TableWidgetData","TableSortDirection","TableSortState","columnId","direction","TableColumn","label","align","width","sortable","formatter","value","row","TableWidgetState","columnOrder","sort","page","pageSize","DEFAULT_TABLE_PAGE_SIZE","DEFAULT_TABLE_PAGE_SIZE_OPTIONS","const","SxProps","Theme","styles","container","width","overflowX","table","minWidth","headerCell","fontWeight","backgroundColor","row","border","rowClickable","cursor","pagination","borderTop","borderColor","paginationActions","display","alignItems","gap","ml","empty","textAlign","color","py","Record","useCallback","useMemo","Box","Checkbox","IconButton","Table","MuiTable","TableBody","TableCell","TableContainer","TableHead","TablePagination","TableRow","MuiTableRow","TableSortLabel","TableProps","MuiTableProps","TablePaginationActionsProps","FirstPage","FirstPageIcon","KeyboardArrowLeft","KeyboardArrowRight","LastPage","LastPageIcon","DEFAULT_TABLE_LABELS","TableLabels","DEFAULT_TABLE_PAGE_SIZE_OPTIONS","TableColumn","TableSortDirection","TableSortState","styles","TableUIProps","columns","rows","T","total","page","pageSize","pageSizeOptions","sort","keyColumn","selection","selectable","onSortChange","next","onPageChange","onPageSizeChange","onSelectionChange","onRowClick","row","onRowHover","labels","Partial","emptyContent","React","ReactNode","size","TableUI","t0","$","_c","t1","t2","t3","undefined","process","env","NODE_ENV","missing","some","r","console","error","t4","_labels","minPageSize","Math","min","showPagination","t5","makePaginationActions","PaginationActions","t6","t7","Set","selectionSet","t8","index","resolveRowId","t9","map","pageRowIds","t10","length","every","id","has","allOnPageSelected","t11","id_0","someOnPageSelected","t12","columnId","direction","sameCol","nextDir","handleSort","t13","filter","id_1","includes","merged","id_2","add","handleSelectAllOnPage","t14","rowId","delete","handleSelectRow","t15","headerCell","selectAll","t16","t17","column","isSorted","align","width","sortable","label","t18","empty","row_0","index_0","rowId_0","isSelected","rowClickable","e","stopPropagation","selectRow","column_0","formatter","stringifyCell","t19","t20","table","t21","_","next_0","e_0","next_1","parseInt","target","value","rowsPerPage","t22","from","to","count","paginationOf","pagination","container","String","Array","isArray","JSON","stringify","lastPage","max","ceil","paginationActions","firstPage","previousPage","nextPage","toCsvString","TableColumn","TableRow","TableSortDirection","TableWidgetData","compareValues","a","b","direction","cmp","localeCompare","JSON","stringify","sortRows","rows","T","columnId","sort","paginateRows","page","pageSize","slice","start","resolveColumns","columns","columnOrder","length","byId","Map","map","c","id","ordered","seen","Set","get","has","push","add","deriveVisibleRows","options","sorted","visible","tableDataToCsv","data","stringifyHeader","label","row","stringifyCell","String","value","Array","isArray","useCallback","useMemo","getWidgetStore","useWidget","useWidgetId","useWidgetShallow","TableUI","TableUIProps","DEFAULT_TABLE_PAGE_SIZE","TableColumn","TableRow","TableSortState","TableWidgetState","deriveVisibleRows","resolveColumns","TableProps","Pick","T","columns","visibleColumns","initialPageSize","selection","onSelectionChange","next","onRowClick","row","onRowHover","remote","total","onSortChange","onPageChange","page","onPageSizeChange","pageSize","Table","t0","$","_c","remoteTotal","t1","t2","uiProps","undefined","id","data","_temp","t3","s_0","sort","s","columnOrder","ui","t4","reordered","slice","orderedColumns","t5","bb0","t6","t7","t8","rows","totalRows","sorted","visible","length","setState","Partial","handleSortChange","handlePageChange","handlePageSizeChange","t9","Box","Skeleton","Table","MuiTable","TableBody","TableCell","TableHead","TableRow","MuiTableRow","TableProps","MuiTableProps","styles","TableSkeletonProps","rows","columns","size","TableSkeleton","t0","$","_c","t1","t2","undefined","t3","Array","from","length","map","_temp","t4","t5","__0","r","row","__","c_0","c","t6","container","table","_","headerCell","buildCsvDownloadItem","buildPngDownloadItem","DownloadContext","DownloadItem","tableDataToCsv","TableColumn","TableWidgetData","createTableDownloadConfig","opts","filename","getData","ctx","columns","getCaptureEl","HTMLElement","pngPixelRatio","pngBackgroundColor","items","push","pixelRatio","backgroundColor","getCsv","filterTableByLockedRows","input","lockedItems","keyColumn","length","Array","isArray","locked","Set","filter","row","index","id","Record","has"],"sources":["../src/widgets-v2/table/labels.tsx","../src/widgets-v2/table/types.ts","../src/widgets-v2/table/style.ts","../src/widgets-v2/table/table-ui.tsx","../src/widgets-v2/table/helpers.ts","../src/widgets-v2/table/table.tsx","../src/widgets-v2/table/skeleton.tsx","../src/widgets-v2/table/download.ts","../src/widgets-v2/table/transforms.ts"],"sourcesContent":["import { Box, type SxProps, type Theme } from '@mui/material'\nimport type { ReactNode } from 'react'\n\nexport interface TableLabels {\n selectAll: string\n selectRow: (rowId: string | number) => string\n rowsPerPage: string\n /**\n * Renders the displayed-rows summary in the pagination footer. Returns\n * a `ReactNode` so the default can emphasise the active range\n * (`from-to`) with a bolder weight while keeping the trailing\n * ` of total` muted. Override to localise wording or restyle.\n */\n paginationOf: (from: number, to: number, total: number) => ReactNode\n /** aria-label for the first-page pagination button. */\n firstPage: string\n /** aria-label for the previous-page pagination button. */\n previousPage: string\n /** aria-label for the next-page pagination button. */\n nextPage: string\n /** aria-label for the last-page pagination button. */\n lastPage: string\n}\n\nconst boldRange: SxProps<Theme> = { fontWeight: 600, color: 'text.primary' }\n\nexport const DEFAULT_TABLE_LABELS: TableLabels = {\n selectAll: 'Select all rows',\n selectRow: (id) => `Select row ${id}`,\n rowsPerPage: 'Rows per page:',\n paginationOf: (from, to, total) => (\n <>\n <Box component='span' sx={boldRange}>{`${from}–${to}`}</Box>\n {` of ${total}`}\n </>\n ),\n firstPage: 'First page',\n previousPage: 'Previous page',\n nextPage: 'Next page',\n lastPage: 'Last page',\n}\n","import type { ReactNode } from 'react'\nimport type { WidgetState } from '../stores'\n\n/**\n * Single row of tabular data.\n *\n * The default row-identity column is `id`. Consumers that don't have a\n * literal `id` field can point `<Table>` / `<TableUI>` at a different\n * column via the `keyColumn` prop; the library reads `row[keyColumn]`\n * for selection lookup, React keys, and aria labels.\n */\nexport interface TableRow extends Record<string, unknown> {\n /**\n * Default row identity. Required when no `keyColumn` is configured.\n * Omit when wiring `keyColumn` to a different column.\n */\n id?: string | number\n}\n\nexport type TableWidgetData = readonly TableRow[]\n\nexport type TableSortDirection = 'asc' | 'desc'\n\nexport interface TableSortState {\n columnId: string | null\n direction: TableSortDirection\n}\n\nexport interface TableColumn {\n /** Unique column identifier; matches the field name on each row. */\n id: string\n /** Header label. */\n label: ReactNode\n align?: 'left' | 'center' | 'right'\n width?: number | string\n sortable?: boolean\n /** Custom cell renderer. Falls back to a string-cast of the raw value. */\n formatter?: (value: unknown, row: TableRow) => ReactNode\n}\n\n/**\n * State extension carrying Table-specific UI state on the per-widget store.\n * Per R12: widget-specific UI state lives in widget-specific extensions of\n * `WidgetState`, not on the base type.\n */\nexport interface TableWidgetState extends WidgetState {\n /** Optional reordered column list driven by ChangeColumn. Falls back to props. */\n columnOrder?: readonly string[]\n sort?: TableSortState\n page: number\n pageSize: number\n}\n\nexport const DEFAULT_TABLE_PAGE_SIZE = 10\nexport const DEFAULT_TABLE_PAGE_SIZE_OPTIONS = [10, 25, 50, 100] as const\n","import type { SxProps, Theme } from '@mui/material'\n\nexport const styles = {\n container: {\n width: '100%',\n overflowX: 'auto',\n },\n\n table: {\n minWidth: 0,\n },\n headerCell: {\n fontWeight: 600,\n backgroundColor: 'background.paper',\n },\n /**\n * Strip the bottom border from the last body row so the body flushes\n * against the pagination border instead of doubling it up. Mirrors v1.\n */\n row: {\n '&:last-child td, &:last-child th': {\n border: 0,\n },\n },\n rowClickable: {\n cursor: 'pointer',\n },\n pagination: {\n borderTop: '1px solid',\n borderColor: 'divider',\n },\n paginationActions: {\n display: 'flex',\n alignItems: 'center',\n gap: 0.25,\n ml: 1,\n },\n empty: {\n textAlign: 'center',\n color: 'text.secondary',\n py: 3,\n },\n} satisfies Record<string, SxProps<Theme>>\n","import { useCallback, useMemo } from 'react'\nimport {\n Box,\n Checkbox,\n IconButton,\n Table as MuiTable,\n TableBody,\n TableCell,\n TableContainer,\n TableHead,\n TablePagination,\n TableRow as MuiTableRow,\n TableSortLabel,\n type TableProps as MuiTableProps,\n} from '@mui/material'\nimport type { TablePaginationActionsProps } from '@mui/material/TablePagination/TablePaginationActions'\nimport { FirstPage as FirstPageIcon } from '@mui/icons-material'\nimport { KeyboardArrowLeft } from '@mui/icons-material'\nimport { KeyboardArrowRight } from '@mui/icons-material'\nimport { LastPage as LastPageIcon } from '@mui/icons-material'\nimport { DEFAULT_TABLE_LABELS, type TableLabels } from './labels'\nimport {\n DEFAULT_TABLE_PAGE_SIZE_OPTIONS,\n type TableColumn,\n type TableRow,\n type TableSortDirection,\n type TableSortState,\n} from './types'\nimport { styles } from './style'\n\nexport interface TableUIProps<T extends TableRow = TableRow> {\n columns: readonly TableColumn[]\n /** Already-paginated, already-sorted rows for the current view. */\n rows: readonly T[]\n /** Total row count (across all pages). Required for pagination footer. */\n total: number\n page: number\n pageSize: number\n pageSizeOptions?: readonly number[]\n sort?: TableSortState\n /**\n * Column name to use as the row identity. Drives selection lookup,\n * React keys, and aria labels. Defaults to `'id'` — point it at\n * another column when your rows don't carry an `id` field.\n */\n keyColumn?: string\n /** Selected row ids. Destination-owned. */\n selection?: readonly (string | number)[]\n selectable?: boolean\n onSortChange?: (next: TableSortState) => void\n onPageChange?: (page: number) => void\n onPageSizeChange?: (pageSize: number) => void\n onSelectionChange?: (next: readonly (string | number)[]) => void\n onRowClick?: (row: T) => void\n onRowHover?: (row: T | null) => void\n labels?: Partial<TableLabels>\n /** Row rendered when `rows` is empty for the current page. */\n emptyContent?: React.ReactNode\n /**\n * Forwarded to MUI's `<Table size>` — `'small'` for compact rows,\n * `'medium'` for the default density. Leave `undefined` (the default)\n * to let MUI's own default kick in.\n */\n size?: MuiTableProps['size']\n}\n\n/**\n * Pure renderer for a paginated, sortable, optionally-selectable table.\n * Has no widget-store coupling — `<Table>` (the bridge) reads from the store\n * and feeds this UI with already-projected data.\n */\nexport function TableUI<T extends TableRow = TableRow>({\n columns,\n rows,\n total,\n page,\n pageSize,\n pageSizeOptions = DEFAULT_TABLE_PAGE_SIZE_OPTIONS,\n sort,\n keyColumn = 'id',\n selection,\n selectable = false,\n onSortChange,\n onPageChange,\n onPageSizeChange,\n onSelectionChange,\n onRowClick,\n onRowHover,\n labels,\n emptyContent,\n size,\n}: TableUIProps<T>) {\n if (process.env.NODE_ENV !== 'production') {\n // Dev-time guard: a nullish identity collapses every row into the\n // same selection-set entry, which manifests as \"click one → all\n // appear selected\". Surface it loudly instead of silently degrading.\n const missing = rows.some((r) => r[keyColumn] == null)\n if (missing) {\n // eslint-disable-next-line no-console\n console.error(\n `<TableUI>: rows are missing the identity column \\`${keyColumn}\\`. ` +\n 'Set the `keyColumn` prop to a column present on every row, or ' +\n 'add the column to the data.',\n )\n }\n }\n const _labels = useMemo(\n () => ({ ...DEFAULT_TABLE_LABELS, ...labels }),\n [labels],\n )\n // Auto-hide the pagination footer when every row already fits in the\n // smallest available page size — the Rows-per-page selector + prev /\n // next buttons would just be inert noise. Consumers force the footer\n // on by passing a smaller `pageSizeOptions[0]` than `total`.\n const minPageSize = Math.min(...pageSizeOptions)\n const showPagination = total > minPageSize\n // Own the `ActionsComponent` slot ourselves so the Meridian theme's\n // `theme.components.MuiTablePagination.defaultProps.ActionsComponent`\n // (which depends on `react-intl`) doesn't leak into the library. The\n // MUI / Meridian style overrides for `MuiIconButton` /\n // `MuiTablePagination` still apply.\n const PaginationActions = useMemo(\n () => makePaginationActions(_labels),\n [_labels],\n )\n const selectionSet = useMemo(\n () => new Set<string | number>(selection ?? []),\n [selection],\n )\n // Resolve each row's identity from `keyColumn`, falling back to the row's\n // index when the cell is nullish. The dev-time guard above surfaces the\n // misconfiguration loudly, but in production we must NOT collapse every\n // nullish-keyed row into the same selection-set entry (that's the\n // \"click one → all selected\" bug) — a per-index fallback keeps ids\n // distinct and React keys stable for a given page.\n const resolveRowId = useCallback(\n (row: T, index: number): string | number =>\n (row[keyColumn] ?? index) as string | number,\n [keyColumn],\n )\n const pageRowIds = useMemo(() => rows.map(resolveRowId), [rows, resolveRowId])\n const allOnPageSelected =\n pageRowIds.length > 0 && pageRowIds.every((id) => selectionSet.has(id))\n const someOnPageSelected =\n !allOnPageSelected && pageRowIds.some((id) => selectionSet.has(id))\n\n const handleSort = (columnId: string) => {\n if (!onSortChange) return\n const sameCol = sort?.columnId === columnId\n const nextDir: TableSortDirection =\n sameCol && sort?.direction === 'asc' ? 'desc' : 'asc'\n onSortChange({ columnId, direction: nextDir })\n }\n\n const handleSelectAllOnPage = () => {\n if (!onSelectionChange) return\n if (allOnPageSelected) {\n onSelectionChange(\n (selection ?? []).filter((id) => !pageRowIds.includes(id)),\n )\n } else {\n const merged = new Set<string | number>(selection ?? [])\n for (const id of pageRowIds) merged.add(id)\n onSelectionChange([...merged])\n }\n }\n\n const handleSelectRow = (rowId: string | number) => {\n if (!onSelectionChange) return\n const next = new Set<string | number>(selection ?? [])\n if (next.has(rowId)) next.delete(rowId)\n else next.add(rowId)\n onSelectionChange([...next])\n }\n\n return (\n <Box sx={styles.container}>\n <TableContainer>\n <MuiTable stickyHeader size={size} sx={styles.table}>\n <TableHead>\n <MuiTableRow>\n {selectable ? (\n <TableCell padding='checkbox' sx={styles.headerCell}>\n <Checkbox\n checked={allOnPageSelected}\n indeterminate={someOnPageSelected}\n onChange={handleSelectAllOnPage}\n inputProps={{ 'aria-label': _labels.selectAll }}\n />\n </TableCell>\n ) : null}\n {columns.map((column) => {\n const isSorted = sort?.columnId === column.id\n const direction = isSorted ? sort?.direction : undefined\n return (\n <TableCell\n key={column.id}\n align={column.align}\n sortDirection={direction}\n sx={styles.headerCell}\n style={\n column.width != null ? { width: column.width } : undefined\n }\n >\n {column.sortable && onSortChange ? (\n <TableSortLabel\n active={isSorted}\n direction={direction ?? 'asc'}\n onClick={() => handleSort(column.id)}\n >\n {column.label}\n </TableSortLabel>\n ) : (\n column.label\n )}\n </TableCell>\n )\n })}\n </MuiTableRow>\n </TableHead>\n <TableBody>\n {rows.length === 0 ? (\n <MuiTableRow>\n <TableCell\n colSpan={columns.length + (selectable ? 1 : 0)}\n sx={styles.empty}\n >\n {emptyContent ?? null}\n </TableCell>\n </MuiTableRow>\n ) : (\n rows.map((row, index) => {\n const rowId = resolveRowId(row, index)\n const isSelected = selectionSet.has(rowId)\n return (\n <MuiTableRow\n key={rowId}\n hover\n selected={isSelected}\n onClick={() => onRowClick?.(row)}\n onMouseEnter={() => onRowHover?.(row)}\n onMouseLeave={() => onRowHover?.(null)}\n sx={{\n ...styles.row,\n ...(onRowClick ? styles.rowClickable : null),\n }}\n >\n {selectable ? (\n <TableCell padding='checkbox'>\n <Checkbox\n checked={isSelected}\n onClick={(e) => {\n e.stopPropagation()\n handleSelectRow(rowId)\n }}\n inputProps={{\n 'aria-label': _labels.selectRow(rowId),\n }}\n />\n </TableCell>\n ) : null}\n {columns.map((column) => (\n <TableCell key={column.id} align={column.align}>\n {column.formatter\n ? column.formatter(row[column.id], row)\n : stringifyCell(row[column.id])}\n </TableCell>\n ))}\n </MuiTableRow>\n )\n })\n )}\n </TableBody>\n </MuiTable>\n </TableContainer>\n {showPagination ? (\n <TablePagination\n component='div'\n count={total}\n page={page}\n rowsPerPage={pageSize}\n rowsPerPageOptions={[...pageSizeOptions]}\n onPageChange={(_, next) => onPageChange?.(next)}\n onRowsPerPageChange={(e) => {\n const next = parseInt(e.target.value, 10)\n onPageSizeChange?.(next)\n }}\n labelRowsPerPage={_labels.rowsPerPage}\n labelDisplayedRows={({ from, to, count }) =>\n _labels.paginationOf(from, to, count)\n }\n ActionsComponent={PaginationActions}\n sx={styles.pagination}\n />\n ) : null}\n </Box>\n )\n}\n\nfunction stringifyCell(value: unknown): React.ReactNode {\n if (value == null) return ''\n if (typeof value === 'string' || typeof value === 'number') return value\n if (typeof value === 'boolean') return String(value)\n if (Array.isArray(value) || typeof value === 'object') {\n return JSON.stringify(value)\n }\n return ''\n}\n\n/**\n * Build the `ActionsComponent` used by `<TablePagination>` — four MUI\n * `IconButton`s for first / previous / next / last. We provide this\n * ourselves so the Meridian theme's `defaultProps.ActionsComponent`\n * (which depends on `react-intl`) is bypassed at the call site without\n * disturbing the rest of the Meridian theme. The factory closes over\n * the merged label set so aria-labels stay consistent with the rest\n * of the table's i18n surface.\n */\nfunction makePaginationActions(labels: TableLabels) {\n return function PaginationActions({\n count,\n page,\n rowsPerPage,\n onPageChange,\n }: TablePaginationActionsProps) {\n const lastPage = Math.max(0, Math.ceil(count / rowsPerPage) - 1)\n return (\n <Box sx={styles.paginationActions}>\n <IconButton\n size='small'\n onClick={(e) => onPageChange(e, 0)}\n disabled={page === 0}\n aria-label={labels.firstPage}\n >\n <FirstPageIcon fontSize='small' />\n </IconButton>\n <IconButton\n size='small'\n onClick={(e) => onPageChange(e, page - 1)}\n disabled={page === 0}\n aria-label={labels.previousPage}\n >\n <KeyboardArrowLeft fontSize='small' />\n </IconButton>\n <IconButton\n size='small'\n onClick={(e) => onPageChange(e, page + 1)}\n disabled={page >= lastPage}\n aria-label={labels.nextPage}\n >\n <KeyboardArrowRight fontSize='small' />\n </IconButton>\n <IconButton\n size='small'\n onClick={(e) => onPageChange(e, lastPage)}\n disabled={page >= lastPage}\n aria-label={labels.lastPage}\n >\n <LastPageIcon fontSize='small' />\n </IconButton>\n </Box>\n )\n }\n}\n","import { toCsvString } from '../actions/download'\nimport type {\n TableColumn,\n TableRow,\n TableSortDirection,\n TableWidgetData,\n} from './types'\n\n/**\n * Compares two values with a consistent ordering across primitive types.\n * Strings use locale comparison; numbers subtract; booleans rank false < true;\n * objects/arrays compare by JSON serialization. Null/undefined sort to the end\n * regardless of direction.\n */\nexport function compareValues(\n a: unknown,\n b: unknown,\n direction: TableSortDirection,\n): number {\n if (a == null && b == null) return 0\n if (a == null) return 1\n if (b == null) return -1\n let cmp = 0\n if (typeof a === 'string' && typeof b === 'string') {\n cmp = a.localeCompare(b)\n } else if (typeof a === 'number' && typeof b === 'number') {\n cmp = a - b\n } else if (typeof a === 'boolean' && typeof b === 'boolean') {\n cmp = a === b ? 0 : a ? 1 : -1\n } else if (typeof a === 'object' || typeof b === 'object') {\n cmp = JSON.stringify(a).localeCompare(JSON.stringify(b))\n }\n return direction === 'asc' ? cmp : -cmp\n}\n\n/** Returns a new array sorted by the named column. Does not mutate the input. */\nexport function sortRows<T extends TableRow>(\n rows: readonly T[],\n columnId: string,\n direction: TableSortDirection,\n): T[] {\n return [...rows].sort((a, b) =>\n compareValues(a[columnId], b[columnId], direction),\n )\n}\n\n/** Returns the slice for the requested page. Out-of-range pages return []. */\nexport function paginateRows<T>(\n rows: readonly T[],\n page: number,\n pageSize: number,\n): T[] {\n if (pageSize <= 0) return rows.slice()\n const start = page * pageSize\n return rows.slice(start, start + pageSize)\n}\n\n/**\n * Resolves the effective column list. When the widget store has a\n * `columnOrder` set (e.g. ChangeColumn was used), the column array is\n * reordered to match. Unknown ids in the order are skipped; columns not\n * present in the order keep their original relative position at the end.\n */\nexport function resolveColumns(\n columns: readonly TableColumn[],\n columnOrder: readonly string[] | undefined,\n): readonly TableColumn[] {\n if (!columnOrder || columnOrder.length === 0) return columns\n const byId = new Map(columns.map((c) => [c.id, c]))\n const ordered: TableColumn[] = []\n const seen = new Set<string>()\n for (const id of columnOrder) {\n const c = byId.get(id)\n if (c && !seen.has(id)) {\n ordered.push(c)\n seen.add(id)\n }\n }\n for (const c of columns) {\n if (!seen.has(c.id)) ordered.push(c)\n }\n return ordered\n}\n\n/** Applies sort and pagination to the input data. Pure. */\nexport function deriveVisibleRows<T extends TableRow>(\n rows: readonly T[],\n options: {\n sort?: { columnId: string | null; direction: TableSortDirection }\n page: number\n pageSize: number\n },\n): { sorted: readonly T[]; visible: T[] } {\n const sorted =\n options.sort?.columnId != null\n ? sortRows(rows, options.sort.columnId, options.sort.direction)\n : rows\n const visible = paginateRows(sorted, options.page, options.pageSize)\n return { sorted, visible }\n}\n\nexport function tableDataToCsv(\n data: TableWidgetData,\n columns: readonly TableColumn[],\n): string {\n // Pre-stringify with the table's own header/cell rules, then delegate the\n // CSV assembly (quoting + spreadsheet formula-injection guard) to the shared\n // `toCsvString` so escaping stays identical to every other widget's export.\n const rows: string[][] = [columns.map((c) => stringifyHeader(c.label))]\n for (const row of data) {\n rows.push(columns.map((c) => stringifyCell(row[c.id])))\n }\n return toCsvString(rows)\n}\n\nfunction stringifyHeader(label: unknown): string {\n if (typeof label === 'string') return label\n if (typeof label === 'number' || typeof label === 'boolean')\n return String(label)\n return ''\n}\n\nfunction stringifyCell(value: unknown): string {\n if (value == null) return ''\n if (typeof value === 'string') return value\n if (typeof value === 'number' || typeof value === 'boolean')\n return String(value)\n if (Array.isArray(value) || typeof value === 'object')\n return JSON.stringify(value)\n return ''\n}\n","import { useCallback, useMemo } from 'react'\nimport {\n getWidgetStore,\n useWidget,\n useWidgetId,\n useWidgetShallow,\n} from '../stores'\nimport { TableUI, type TableUIProps } from './table-ui'\nimport {\n DEFAULT_TABLE_PAGE_SIZE,\n type TableColumn,\n type TableRow,\n type TableSortState,\n type TableWidgetState,\n} from './types'\nimport { deriveVisibleRows, resolveColumns } from './helpers'\n\nexport interface TableProps<T extends TableRow = TableRow> extends Pick<\n TableUIProps<T>,\n | 'pageSizeOptions'\n | 'selectable'\n | 'labels'\n | 'emptyContent'\n | 'size'\n | 'keyColumn'\n> {\n /**\n * Column definitions. Order can be overridden by ChangeColumn via the\n * `columnOrder` field on the extended widget state.\n */\n columns: readonly TableColumn[]\n /**\n * When set, render only the first `visibleColumns` entries **after**\n * applying the user's `columnOrder` from the store. Useful for showing\n * a compact projection while letting consumers (e.g. `Widget.ChangeColumn`)\n * see the full column list. When omitted, every column renders.\n */\n visibleColumns?: number\n /** Initial page size (only on first mount; afterwards lives on the store). */\n initialPageSize?: number\n /** Selected row ids (destination-owned). */\n selection?: readonly (string | number)[]\n onSelectionChange?: (next: readonly (string | number)[]) => void\n onRowClick?: (row: T) => void\n onRowHover?: (row: T | null) => void\n /**\n * When `true`, the bridge stops sorting and paginating locally and\n * renders `data` as-is — the consumer is then responsible for\n * refetching the slice that matches the active `page` / `pageSize` /\n * `sort` from the outbound callbacks below. `total` is required in\n * this mode (the server already knows the full row count; the\n * widget can't infer it from a partial page).\n */\n remote?: boolean\n /**\n * Server-reported total row count. Required when `remote === true`;\n * ignored in local mode (where the bridge derives total from the\n * sorted result of `deriveVisibleRows`).\n */\n total?: number\n /** Fires after the store-level sort write so the consumer can refetch. */\n onSortChange?: (next: TableSortState) => void\n /** Fires after the store-level page write so the consumer can refetch. */\n onPageChange?: (page: number) => void\n /** Fires after the store-level pageSize write so the consumer can refetch. */\n onPageSizeChange?: (pageSize: number) => void\n}\n\n/**\n * Bridge component — reads the widget store's `data`, applies sort + pagination\n * locally, and feeds `<TableUI />`. Sort, page, and pageSize live on the\n * extended widget state ({@link TableWidgetState}).\n */\nexport function Table<T extends TableRow = TableRow>({\n columns,\n visibleColumns,\n initialPageSize = DEFAULT_TABLE_PAGE_SIZE,\n selection,\n onSelectionChange,\n onRowClick,\n onRowHover,\n remote = false,\n total: remoteTotal,\n onSortChange,\n onPageChange,\n onPageSizeChange,\n ...uiProps\n}: TableProps<T>) {\n const id = useWidgetId()\n const data = useWidget(id, (s) => s.data as readonly T[] | undefined)\n const ui = useWidgetShallow<\n {\n sort: TableSortState | undefined\n page: number\n pageSize: number\n columnOrder: readonly string[] | undefined\n },\n TableWidgetState\n >(id, (s) => ({\n sort: s.sort,\n page: s.page ?? 0,\n pageSize: s.pageSize ?? initialPageSize,\n columnOrder: s.columnOrder,\n }))\n\n const orderedColumns = useMemo(() => {\n const reordered = resolveColumns(columns, ui.columnOrder)\n return visibleColumns == null\n ? reordered\n : reordered.slice(0, visibleColumns)\n }, [columns, ui.columnOrder, visibleColumns])\n\n // In remote mode the consumer already paginated / sorted server-side,\n // so pass `data` and `total` straight through. Local mode keeps the\n // bridge-driven sort + slice via `deriveVisibleRows`.\n const { rows, totalRows } = useMemo(() => {\n if (remote) {\n return {\n rows: data ?? [],\n totalRows: remoteTotal ?? 0,\n }\n }\n const { sorted, visible } = deriveVisibleRows(data ?? [], {\n sort: ui.sort,\n page: ui.page,\n pageSize: ui.pageSize,\n })\n return { rows: visible, totalRows: sorted.length }\n }, [remote, data, remoteTotal, ui.sort, ui.page, ui.pageSize])\n\n const handleSortChange = useCallback(\n (next: TableSortState) => {\n getWidgetStore(id).setState({\n sort: next,\n page: 0,\n } as Partial<TableWidgetState>)\n onSortChange?.(next)\n },\n [id, onSortChange],\n )\n\n const handlePageChange = useCallback(\n (page: number) => {\n getWidgetStore(id).setState({ page } as Partial<TableWidgetState>)\n onPageChange?.(page)\n },\n [id, onPageChange],\n )\n\n const handlePageSizeChange = useCallback(\n (pageSize: number) => {\n getWidgetStore(id).setState({\n pageSize,\n page: 0,\n } as Partial<TableWidgetState>)\n onPageSizeChange?.(pageSize)\n },\n [id, onPageSizeChange],\n )\n\n return (\n <TableUI\n {...uiProps}\n columns={orderedColumns}\n rows={rows}\n total={totalRows}\n page={ui.page}\n pageSize={ui.pageSize}\n sort={ui.sort}\n selection={selection}\n onSortChange={handleSortChange}\n onPageChange={handlePageChange}\n onPageSizeChange={handlePageSizeChange}\n onSelectionChange={onSelectionChange}\n onRowClick={onRowClick}\n onRowHover={onRowHover}\n />\n )\n}\n","import {\n Box,\n Skeleton,\n Table as MuiTable,\n TableBody,\n TableCell,\n TableHead,\n TableRow as MuiTableRow,\n type TableProps as MuiTableProps,\n} from '@mui/material'\nimport { styles } from './style'\n\nexport interface TableSkeletonProps {\n /** Number of body rows to render. Defaults to `5` (matches v1). */\n rows?: number\n /** Number of columns to render. Defaults to `4` (matches v1). */\n columns?: number\n /**\n * Forwarded to MUI's `<Table size>` so the loading layout matches the\n * size you'll render in {@link TableUI}. Leave `undefined` (the\n * default) to use MUI's own default density.\n */\n size?: MuiTableProps['size']\n}\n\n/**\n * Loading placeholder for the Table widget. Renders the same MUI table\n * primitives that {@link TableUI} uses so the loading layout (column\n * widths, header band, row density) doesn't shift when data resolves.\n *\n * Mirrors the v1 widget's `<TableSkeleton>` structure with v2's themed\n * `styles.headerCell`.\n */\nexport function TableSkeleton({\n rows = 5,\n columns = 4,\n size,\n}: TableSkeletonProps) {\n return (\n <Box sx={styles.container} aria-label='Table skeleton'>\n <MuiTable size={size} sx={styles.table} stickyHeader>\n <TableHead>\n <MuiTableRow>\n {Array.from({ length: columns }).map((_, c) => (\n <TableCell key={`head-${c}`} sx={styles.headerCell}>\n <Skeleton variant='text' width='80%' height={24} />\n </TableCell>\n ))}\n </MuiTableRow>\n </TableHead>\n <TableBody>\n {Array.from({ length: rows }).map((_, r) => (\n <MuiTableRow key={`row-${r}`} sx={styles.row}>\n {Array.from({ length: columns }).map((__, c) => (\n <TableCell key={`cell-${r}-${c}`}>\n <Skeleton variant='text' width='70%' height={20} />\n </TableCell>\n ))}\n </MuiTableRow>\n ))}\n </TableBody>\n </MuiTable>\n </Box>\n )\n}\n","import {\n buildCsvDownloadItem,\n buildPngDownloadItem,\n type DownloadContext,\n type DownloadItem,\n} from '../actions/download'\nimport { tableDataToCsv } from './helpers'\nimport type { TableColumn, TableWidgetData } from './types'\n\n/**\n * Download menu items for the Table widget. Always includes a CSV item\n * that pulls the latest data from the widget store via `getData()` (so\n * locked / sorted / filtered state is honored); headers come from\n * `column.label`, cells from `row[column.id]`. When `getCaptureEl` is\n * supplied, prepends a PNG item that rasterises the captured element via\n * `html2canvas`.\n */\nexport function createTableDownloadConfig(opts: {\n filename: string\n getData: (ctx: DownloadContext) => TableWidgetData\n columns: readonly TableColumn[]\n getCaptureEl?: (ctx: DownloadContext) => HTMLElement | null\n pngPixelRatio?: number\n pngBackgroundColor?: string | null\n}): DownloadItem[] {\n const items: DownloadItem[] = []\n if (opts.getCaptureEl) {\n items.push(\n buildPngDownloadItem({\n filename: opts.filename,\n getCaptureEl: opts.getCaptureEl,\n pixelRatio: opts.pngPixelRatio,\n backgroundColor: opts.pngBackgroundColor,\n }),\n )\n }\n items.push(\n buildCsvDownloadItem({\n filename: opts.filename,\n getCsv: (ctx) => tableDataToCsv(opts.getData(ctx), opts.columns),\n }),\n )\n return items\n}\n","/**\n * `LockSelection` filter for Table. Data is a FLAT `TableRow[]` (unlike every\n * other widget's `X[][]` series shape) and row identity comes from\n * `row[keyColumn]` (default `'id'`), not `name` — so `filterByLockedItems`\n * doesn't apply here (its outer `.map` treats each row as a \"series\", and a\n * plain row object isn't an array, so it would silently pass everything\n * through unfiltered). Falls back to the row's index when the identity\n * column is nullish, mirroring `TableUI`'s own `resolveRowId`.\n *\n * `keyColumn` isn't part of `LockSelection`'s generic `filterFn` signature —\n * close over it: `filterFn={(data, locked) => filterTableByLockedRows(data, locked, keyColumn)}`.\n */\nexport function filterTableByLockedRows(\n input: unknown,\n lockedItems: readonly (string | number)[],\n keyColumn = 'id',\n): unknown {\n if (lockedItems.length === 0) return input\n if (!Array.isArray(input)) return input\n const locked = new Set<string | number>(lockedItems)\n return input.filter((row: unknown, index: number): boolean => {\n if (row == null || typeof row !== 'object') return false\n const id = (row as Record<string, unknown>)[keyColumn] ?? index\n return (typeof id === 'string' || typeof id === 'number') && locked.has(id)\n })\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DownloadItem } from './types.js';
|
|
1
|
+
import { DownloadContext, DownloadItem } from './types.js';
|
|
2
2
|
interface BuildCsvDownloadItemBase {
|
|
3
3
|
/** Base filename (without extension). The item appends `.csv`. */
|
|
4
4
|
filename: string;
|
|
@@ -17,7 +17,7 @@ export type BuildCsvDownloadItemArgs = (BuildCsvDownloadItemBase & {
|
|
|
17
17
|
* through `toCsvString` so escaping (incl. the spreadsheet
|
|
18
18
|
* formula-injection guard) stays consistent across widgets.
|
|
19
19
|
*/
|
|
20
|
-
getRows: () => readonly (readonly unknown[])[];
|
|
20
|
+
getRows: (ctx: DownloadContext) => readonly (readonly unknown[])[];
|
|
21
21
|
getCsv?: never;
|
|
22
22
|
}) | (BuildCsvDownloadItemBase & {
|
|
23
23
|
/**
|
|
@@ -25,7 +25,7 @@ export type BuildCsvDownloadItemArgs = (BuildCsvDownloadItemBase & {
|
|
|
25
25
|
* (e.g. Table) that already serialise their own CSV with bespoke
|
|
26
26
|
* header/cell handling.
|
|
27
27
|
*/
|
|
28
|
-
getCsv: () => string;
|
|
28
|
+
getCsv: (ctx: DownloadContext) => string;
|
|
29
29
|
getRows?: never;
|
|
30
30
|
});
|
|
31
31
|
/**
|
|
@@ -4,5 +4,5 @@ export { CSVIcon, PNGIcon, MarkdownIcon } from './icons.js';
|
|
|
4
4
|
export { buildPngDownloadItem, type BuildPngDownloadItemArgs } from './png-item.js';
|
|
5
5
|
export { buildCsvDownloadItem, type BuildCsvDownloadItemArgs } from './csv-item.js';
|
|
6
6
|
export { DOWNLOAD_ITEM_IDS, type DownloadItemId } from './constants.js';
|
|
7
|
-
export type { DownloadItem } from './types.js';
|
|
7
|
+
export type { DownloadItem, DownloadContext } from './types.js';
|
|
8
8
|
export { DEFAULT_DOWNLOAD_LABELS, type DownloadLabels } from './labels.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DownloadItem } from './types.js';
|
|
1
|
+
import { DownloadContext, DownloadItem } from './types.js';
|
|
2
2
|
export interface BuildPngDownloadItemArgs {
|
|
3
3
|
/** Base filename (without extension). The item appends `.png`. */
|
|
4
4
|
filename: string;
|
|
@@ -7,7 +7,7 @@ export interface BuildPngDownloadItemArgs {
|
|
|
7
7
|
* download config doesn't capture a stale reference. Wire it to
|
|
8
8
|
* `() => getCaptureEl(id)` from `widgets-v2/stores`.
|
|
9
9
|
*/
|
|
10
|
-
getCaptureEl: () => HTMLElement | null;
|
|
10
|
+
getCaptureEl: (ctx: DownloadContext) => HTMLElement | null;
|
|
11
11
|
/** html2canvas `scale`. Default 2. */
|
|
12
12
|
pixelRatio?: number;
|
|
13
13
|
/** html2canvas `backgroundColor`. Default transparent (`null`). */
|