diff options
| author | kj_sh604 | 2026-03-15 16:19:35 -0400 |
|---|---|---|
| committer | kj_sh604 | 2026-03-15 16:19:35 -0400 |
| commit | 6ec259a0e71174651bae95d4628138bf6fd68742 (patch) | |
| tree | 5e33c6a5ec091ecabfcb257fdc7b6a88ed8754ac /packages/excalidraw/components/PasteChartDialog.tsx | |
| parent | 16c8578b15c727f22921f8a80a56ee4d4e7f2272 (diff) | |
refactor: packages/
Diffstat (limited to 'packages/excalidraw/components/PasteChartDialog.tsx')
| -rw-r--r-- | packages/excalidraw/components/PasteChartDialog.tsx | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/packages/excalidraw/components/PasteChartDialog.tsx b/packages/excalidraw/components/PasteChartDialog.tsx new file mode 100644 index 0000000..08a5634 --- /dev/null +++ b/packages/excalidraw/components/PasteChartDialog.tsx @@ -0,0 +1,136 @@ +import oc from "open-color"; +import React, { useLayoutEffect, useRef, useState } from "react"; +import { trackEvent } from "../analytics"; +import type { ChartElements, Spreadsheet } from "../charts"; +import { renderSpreadsheet } from "../charts"; +import type { ChartType } from "../element/types"; +import { t } from "../i18n"; +import { exportToSvg } from "../scene/export"; +import type { UIAppState } from "../types"; +import { useApp } from "./App"; +import { Dialog } from "./Dialog"; + +import "./PasteChartDialog.scss"; + +type OnInsertChart = (chartType: ChartType, elements: ChartElements) => void; + +const ChartPreviewBtn = (props: { + spreadsheet: Spreadsheet | null; + chartType: ChartType; + selected: boolean; + onClick: OnInsertChart; +}) => { + const previewRef = useRef<HTMLDivElement | null>(null); + const [chartElements, setChartElements] = useState<ChartElements | null>( + null, + ); + + useLayoutEffect(() => { + if (!props.spreadsheet) { + return; + } + + const elements = renderSpreadsheet( + props.chartType, + props.spreadsheet, + 0, + 0, + ); + setChartElements(elements); + let svg: SVGSVGElement; + const previewNode = previewRef.current!; + + (async () => { + svg = await exportToSvg( + elements, + { + exportBackground: false, + viewBackgroundColor: oc.white, + }, + null, // files + { + skipInliningFonts: true, + }, + ); + svg.querySelector(".style-fonts")?.remove(); + previewNode.replaceChildren(); + previewNode.appendChild(svg); + + if (props.selected) { + (previewNode.parentNode as HTMLDivElement).focus(); + } + })(); + + return () => { + previewNode.replaceChildren(); + }; + }, [props.spreadsheet, props.chartType, props.selected]); + + return ( + <button + type="button" + className="ChartPreview" + onClick={() => { + if (chartElements) { + props.onClick(props.chartType, chartElements); + } + }} + > + <div ref={previewRef} /> + </button> + ); +}; + +export const PasteChartDialog = ({ + setAppState, + appState, + onClose, +}: { + appState: UIAppState; + onClose: () => void; + setAppState: React.Component<any, UIAppState>["setState"]; +}) => { + const { onInsertElements } = useApp(); + const handleClose = React.useCallback(() => { + if (onClose) { + onClose(); + } + }, [onClose]); + + const handleChartClick = (chartType: ChartType, elements: ChartElements) => { + onInsertElements(elements); + trackEvent("paste", "chart", chartType); + setAppState({ + currentChartType: chartType, + pasteDialog: { + shown: false, + data: null, + }, + }); + }; + + return ( + <Dialog + size="small" + onCloseRequest={handleClose} + title={t("labels.pasteCharts")} + className={"PasteChartDialog"} + autofocus={false} + > + <div className={"container"}> + <ChartPreviewBtn + chartType="bar" + spreadsheet={appState.pasteDialog.data} + selected={appState.currentChartType === "bar"} + onClick={handleChartClick} + /> + <ChartPreviewBtn + chartType="line" + spreadsheet={appState.pasteDialog.data} + selected={appState.currentChartType === "line"} + onClick={handleChartClick} + /> + </div> + </Dialog> + ); +}; |
