SqlMonacoBlock.tsx87 lines · main
1import Editor from '@monaco-editor/react'
2import { Check, Copy } from 'lucide-react'
3import { useMemo, useState } from 'react'
4import { Button, cn, copyToClipboard } from 'ui'
5
6type SqlMonacoBlockProps = {
7 value?: string
8 className?: string
9 wrapperClassName?: string
10 hideCopy?: boolean
11 // Fixed height in px. Defaults to 310 to match previous CodeBlock max height
12 height?: number
13 // Show line numbers. Defaults to false to match previous CodeBlock
14 lineNumbers?: 'on' | 'off'
15}
16
17export const SqlMonacoBlock = ({
18 value,
19 className,
20 wrapperClassName,
21 height = 310,
22 lineNumbers = 'off',
23 hideCopy = false,
24}: SqlMonacoBlockProps) => {
25 const [copied, setCopied] = useState(false)
26
27 const content = useMemo(() => value ?? '', [value])
28
29 const handleCopy = (value: string) => {
30 setCopied(true)
31 copyToClipboard(value)
32 setTimeout(() => setCopied(false), 1000)
33 }
34
35 return (
36 <div
37 className={cn('group relative border rounded-md overflow-hidden w-full', wrapperClassName)}
38 >
39 <Editor
40 theme="briven"
41 language="pgsql"
42 value={content}
43 height={height}
44 className={className}
45 wrapperProps={{
46 className:
47 '[&_.monaco-editor]:bg-transparent! [&_.monaco-editor-background]:bg-transparent! [&_.monaco-editor]:outline-transparent! [&_.cursor]:hidden!',
48 }}
49 options={{
50 readOnly: true,
51 domReadOnly: true,
52 fontSize: 13,
53 minimap: { enabled: false },
54 lineNumbers,
55 renderLineHighlight: 'none',
56 scrollbar: { vertical: 'auto', horizontal: 'auto' },
57 overviewRulerLanes: 0,
58 overviewRulerBorder: false,
59 glyphMargin: false,
60 folding: false,
61 lineDecorationsWidth: 0,
62 lineNumbersMinChars: lineNumbers === 'off' ? 0 : 3,
63 wordWrap: 'on',
64 scrollBeyondLastLine: false,
65 selectionHighlight: false,
66 occurrencesHighlight: 'off',
67 fixedOverflowWidgets: true,
68 padding: { top: 12, bottom: 12 },
69 tabIndex: -1,
70 }}
71 />
72
73 {!hideCopy && (
74 <div className="absolute right-2 top-2 opacity-0 group-hover:opacity-100 transition-opacity">
75 <Button
76 type="default"
77 className="px-1.5"
78 icon={copied ? <Check /> : <Copy />}
79 onClick={() => handleCopy(content)}
80 >
81 {copied ? 'Copied' : ''}
82 </Button>
83 </div>
84 )}
85 </div>
86 )
87}