import { RangeSetBuilder } from "@codemirror/rangeset"; import { JSONHeroPath } from "@jsonhero/path"; import { useCodeMirror, EditorView, Decoration, Facet, ViewPlugin, Compartment, TransactionSpec, } from "@uiw/react-codemirror"; import jsonMap from "json-source-map"; import { useRef, useEffect, useMemo, useState } from "react"; import { getPreviewSetup } from "~/utilities/codeMirrorSetup"; import { lightTheme, darkTheme } from "~/utilities/codeMirrorTheme"; import { CopyTextButton } from "./CopyTextButton"; import { useTheme } from "./ThemeProvider"; import {usePreferences} from '~/components/PreferencesProvider'; import { useHotkeys } from "react-hotkeys-hook"; export type JsonPreviewProps = { json: unknown; highlightPath?: string; }; export function JsonPreview({ json, highlightPath }: JsonPreviewProps) { const editor = useRef(null); const [preferences] = usePreferences(); const jsonMapped = useMemo(() => { return jsonMap.stringify(json, null, preferences?.indent || 2); }, [json, preferences]); const lines: LineRange | undefined = useMemo(() => { if (!highlightPath) { return; } let path = new JSONHeroPath(highlightPath); let pointer = path.jsonPointer(); let selectionInfo = jsonMapped.pointers[pointer]; return { from: selectionInfo.value.line + 1, to: selectionInfo.valueEnd.line + 1, }; }, [jsonMapped, highlightPath]); const extensions = getPreviewSetup(); const highlighting = new Compartment(); if (lines) { extensions.push(highlighting.of(highlightLineRange(lines))); } const [theme] = useTheme(); const { setContainer, view, state } = useCodeMirror({ container: editor.current, extensions, value: jsonMapped.json, editable: false, contentEditable: false, autoFocus: false, basicSetup: false, theme: theme === "light" ? lightTheme() : darkTheme(), }); useEffect(() => { if (editor.current) { setContainer(editor.current); } }, [editor.current]); useEffect(() => { if (!view) { return; } let transactionSpec: TransactionSpec = { changes: { from: 0, to: view.state.doc.length, insert: jsonMapped.json }, }; let range = lines; if (range != null) { transactionSpec.effects = highlighting.reconfigure( highlightLineRange(range) ); } view.dispatch(transactionSpec); }, [view, highlighting, jsonMapped, highlightPath]); useHotkeys( "ctrl+a,meta+a,command+a", (e) => { e.preventDefault(); view?.dispatch({ selection: { anchor: 0, head: state?.doc.length } }); }, [view, state] ); const [hovering, setHovering] = useState(false); return (