ResizableAIWidget.tsx 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. import type { editor as monacoEditor } from 'monaco-editor'
  2. import { useCallback, useEffect, useRef, useState } from 'react'
  3. import { AskAIWidget } from '@/components/interfaces/SQLEditor/AskAIWidget'
  4. import InlineWidget from '@/components/interfaces/SQLEditor/InlineWidget'
  5. interface ResizableAIWidgetProps {
  6. editor: monacoEditor.IStandaloneCodeEditor | monacoEditor.IStandaloneDiffEditor
  7. id: string
  8. value: string
  9. onChange: (value: string) => void
  10. onSubmit: (prompt: string) => void
  11. onAccept?: () => void
  12. onReject?: () => void
  13. onCancel?: () => void
  14. isDiffVisible: boolean
  15. isLoading?: boolean
  16. startLineNumber: number
  17. endLineNumber: number
  18. }
  19. const LINE_HEIGHT = 20 // height of each line in pixels
  20. const MIN_LINES = 3 // minimum number of lines to show
  21. const ResizableAIWidget = ({
  22. editor,
  23. id,
  24. value,
  25. onChange,
  26. onSubmit,
  27. onAccept,
  28. onReject,
  29. onCancel,
  30. isDiffVisible,
  31. isLoading = false,
  32. startLineNumber,
  33. endLineNumber,
  34. }: ResizableAIWidgetProps) => {
  35. const containerRef = useRef<HTMLDivElement>(null)
  36. const [heightInLines, setHeightInLines] = useState(MIN_LINES)
  37. const updateHeight = useCallback(() => {
  38. if (containerRef.current) {
  39. const height = containerRef.current.offsetHeight
  40. const newHeightInLines = Math.max(MIN_LINES, Math.ceil(height / LINE_HEIGHT))
  41. setHeightInLines(newHeightInLines)
  42. }
  43. }, [])
  44. useEffect(() => {
  45. // Update height on value change
  46. updateHeight()
  47. // Set up resize observer to track height changes
  48. const resizeObserver = new ResizeObserver(updateHeight)
  49. if (containerRef.current) {
  50. resizeObserver.observe(containerRef.current)
  51. }
  52. return () => {
  53. resizeObserver.disconnect()
  54. }
  55. }, [updateHeight])
  56. return (
  57. <InlineWidget
  58. editor={editor}
  59. id={id}
  60. heightInLines={heightInLines}
  61. afterLineNumber={endLineNumber}
  62. beforeLineNumber={Math.max(0, startLineNumber - 1)}
  63. >
  64. <div ref={containerRef}>
  65. <AskAIWidget
  66. value={value}
  67. onChange={onChange}
  68. onSubmit={onSubmit}
  69. onAccept={onAccept}
  70. onReject={onReject}
  71. onCancel={onCancel}
  72. isDiffVisible={isDiffVisible}
  73. isLoading={isLoading}
  74. />
  75. </div>
  76. </InlineWidget>
  77. )
  78. }
  79. export default ResizableAIWidget