@stack-spot/ai-chat-widget 0.5.0 → 0.7.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.
Files changed (73) hide show
  1. package/dist/StackspotAIWidget.d.ts.map +1 -1
  2. package/dist/StackspotAIWidget.js +3 -2
  3. package/dist/StackspotAIWidget.js.map +1 -1
  4. package/dist/features.d.ts +1 -1
  5. package/dist/features.d.ts.map +1 -1
  6. package/dist/features.js +1 -0
  7. package/dist/features.js.map +1 -1
  8. package/dist/state/ChatEntry.d.ts +1 -1
  9. package/dist/state/ChatEntry.d.ts.map +1 -1
  10. package/dist/state/ChatEntry.js +2 -2
  11. package/dist/state/ChatEntry.js.map +1 -1
  12. package/dist/state/ChatState.d.ts +15 -1
  13. package/dist/state/ChatState.d.ts.map +1 -1
  14. package/dist/state/ChatState.js.map +1 -1
  15. package/dist/state/WidgetState.d.ts +0 -4
  16. package/dist/state/WidgetState.d.ts.map +1 -1
  17. package/dist/state/WidgetState.js.map +1 -1
  18. package/dist/utils/chat.d.ts.map +1 -1
  19. package/dist/utils/chat.js +2 -3
  20. package/dist/utils/chat.js.map +1 -1
  21. package/dist/utils/programming-languages.d.ts +6 -0
  22. package/dist/utils/programming-languages.d.ts.map +1 -0
  23. package/dist/utils/programming-languages.js +463 -0
  24. package/dist/utils/programming-languages.js.map +1 -0
  25. package/dist/views/Agents.js +4 -5
  26. package/dist/views/Agents.js.map +1 -1
  27. package/dist/views/Chat/ChatMessage.d.ts.map +1 -1
  28. package/dist/views/Chat/ChatMessage.js +5 -3
  29. package/dist/views/Chat/ChatMessage.js.map +1 -1
  30. package/dist/views/Chat/styled.d.ts.map +1 -1
  31. package/dist/views/Chat/styled.js +8 -0
  32. package/dist/views/Chat/styled.js.map +1 -1
  33. package/dist/views/ChatHistory/HistoryItem.d.ts.map +1 -1
  34. package/dist/views/ChatHistory/HistoryItem.js +4 -2
  35. package/dist/views/ChatHistory/HistoryItem.js.map +1 -1
  36. package/dist/views/ChatHistory/utils.d.ts +2 -1
  37. package/dist/views/ChatHistory/utils.d.ts.map +1 -1
  38. package/dist/views/ChatHistory/utils.js.map +1 -1
  39. package/dist/views/Editor.d.ts.map +1 -1
  40. package/dist/views/Editor.js +87 -1
  41. package/dist/views/Editor.js.map +1 -1
  42. package/dist/views/MessageInput/ButtonGroup.d.ts.map +1 -1
  43. package/dist/views/MessageInput/ButtonGroup.js +2 -2
  44. package/dist/views/MessageInput/ButtonGroup.js.map +1 -1
  45. package/dist/views/MessageInput/InfoBar.d.ts.map +1 -1
  46. package/dist/views/MessageInput/InfoBar.js +9 -2
  47. package/dist/views/MessageInput/InfoBar.js.map +1 -1
  48. package/dist/views/MessageInput/dictionary.d.ts +1 -1
  49. package/dist/views/MessageInput/dictionary.d.ts.map +1 -1
  50. package/dist/views/MessageInput/dictionary.js +4 -0
  51. package/dist/views/MessageInput/dictionary.js.map +1 -1
  52. package/dist/views/MessageInput/index.d.ts.map +1 -1
  53. package/dist/views/MessageInput/index.js +4 -1
  54. package/dist/views/MessageInput/index.js.map +1 -1
  55. package/package.json +3 -1
  56. package/src/StackspotAIWidget.tsx +3 -1
  57. package/src/chat-interceptors/send-message.ts +1 -1
  58. package/src/features.ts +2 -1
  59. package/src/state/ChatEntry.ts +2 -2
  60. package/src/state/ChatState.ts +13 -1
  61. package/src/state/WidgetState.ts +0 -4
  62. package/src/utils/chat.ts +2 -3
  63. package/src/utils/programming-languages.ts +462 -0
  64. package/src/views/Agents.tsx +4 -4
  65. package/src/views/Chat/ChatMessage.tsx +16 -7
  66. package/src/views/Chat/styled.ts +8 -0
  67. package/src/views/ChatHistory/HistoryItem.tsx +4 -2
  68. package/src/views/ChatHistory/utils.ts +2 -1
  69. package/src/views/Editor.tsx +126 -1
  70. package/src/views/MessageInput/ButtonGroup.tsx +6 -1
  71. package/src/views/MessageInput/InfoBar.tsx +14 -1
  72. package/src/views/MessageInput/dictionary.ts +4 -0
  73. package/src/views/MessageInput/index.tsx +4 -1
@@ -1 +1,126 @@
1
- export const Editor = () => null
1
+ import { Text } from '@citric/core'
2
+ import { LoadingCircular } from '@citric/ui'
3
+ import MonacoEditor, { OnMount } from '@monaco-editor/react'
4
+ import { Select } from '@stack-spot/portal-components/Select'
5
+ import { useThemeKind } from '@stack-spot/portal-theme'
6
+ import { Dictionary, useTranslate } from '@stack-spot/portal-translate'
7
+ import { debounce } from 'lodash'
8
+ import { IDisposable } from 'monaco-editor'
9
+ import { useCallback, useEffect, useMemo, useRef } from 'react'
10
+ import { styled } from 'styled-components'
11
+ import { useCurrentChat, useCurrentChatState, useWidget, useWidgetState } from '../context/hooks'
12
+ import { useRightPanel } from '../right-panel/hooks'
13
+ import { languages } from '../utils/programming-languages'
14
+
15
+ const DEFAULT_LANGUAGE = 'python'
16
+ const MIN_SELECTION_UPDATE_MS = 200
17
+
18
+ const EditorBox = styled.div`
19
+ flex: 1;
20
+
21
+ .monaco-editor {
22
+ --vscode-editor-background: transparent !important;
23
+ --vscode-editorGutter-background: transparent !important;
24
+ }
25
+ `
26
+
27
+ const TitleBox = styled.div`
28
+ .language-selector {
29
+ width: 150px;
30
+ position: absolute;
31
+ top: 21px;
32
+ right: 61px;
33
+
34
+ .options {
35
+ max-height: 250px;
36
+ }
37
+
38
+ .current-value {
39
+ padding: 2px 8px;
40
+ }
41
+ }
42
+ `
43
+
44
+ export const Editor = () => {
45
+ const t = useTranslate(dictionary)
46
+ const panel = useWidgetState('panel')
47
+ const { open } = useRightPanel()
48
+ const widget = useWidget()
49
+ const chat = useCurrentChat()
50
+
51
+ useEffect(() => {
52
+ if (panel === 'editor') open(
53
+ <EditorPanel key={chat.id} />,
54
+ {
55
+ title: <Title key={chat.id} />,
56
+ description: t.description,
57
+ onClose: () => widget.set('panel', undefined),
58
+ },
59
+ )
60
+ }, [panel, t, chat])
61
+
62
+ return null
63
+ }
64
+
65
+ const Title = () => {
66
+ const languageValue = useCurrentChatState('codeLanguage') || DEFAULT_LANGUAGE
67
+ const language = useMemo(() => languages.find(l => l.value === languageValue), [languageValue])
68
+ const chat = useCurrentChat()
69
+ return (
70
+ <TitleBox>
71
+ <Text appearance="h5">Editor</Text>
72
+ <Select
73
+ options={languages}
74
+ renderLabel={l => l.label}
75
+ renderValue={l => l.value}
76
+ value={language}
77
+ onChange={l => chat.set('codeLanguage', l.value)}
78
+ className="language-selector"
79
+ />
80
+ </TitleBox>
81
+ )
82
+ }
83
+
84
+ const EditorPanel = () => {
85
+ const themeKind = useThemeKind()
86
+ const value = useCurrentChatState('code')
87
+ const language = useCurrentChatState('codeLanguage') || DEFAULT_LANGUAGE
88
+ const chat = useCurrentChat()
89
+ const selectionObserver = useRef<IDisposable | undefined>()
90
+
91
+ const setup: OnMount = useCallback((editor) => {
92
+ selectionObserver.current = editor.onDidChangeCursorSelection(debounce((e) => {
93
+ const selectedText = editor.getModel()?.getValueInRange(e.selection)
94
+ chat.set('codeSelection', selectedText?.trim() ? selectedText : undefined)
95
+ }, MIN_SELECTION_UPDATE_MS))
96
+ }, [])
97
+
98
+ useEffect(() => () => {
99
+ chat.set('codeSelection', undefined)
100
+ selectionObserver.current?.dispose()
101
+ }, [])
102
+
103
+ return (
104
+ <EditorBox>
105
+ <MonacoEditor
106
+ height="100%"
107
+ language={language}
108
+ theme={themeKind === 'dark' ? 'vs-dark' : 'light'}
109
+ options={{ minimap: { enabled: false } }}
110
+ value={value}
111
+ onChange={v => chat.set('code', v)}
112
+ loading={<LoadingCircular />}
113
+ onMount={setup}
114
+ />
115
+ </EditorBox>
116
+ )
117
+ }
118
+
119
+ const dictionary = {
120
+ en: {
121
+ description: 'The selected code in the editor below will be used as part of your questions.',
122
+ },
123
+ pt: {
124
+ description: 'O código selecionado no editor abaixo será usado como parte das suas perguntas.',
125
+ },
126
+ } satisfies Dictionary
@@ -1,4 +1,4 @@
1
- import { ChevronRight, KnowledgeSource, Send, Stack, Times, Workspace } from '@citric/icons'
1
+ import { ChevronRight, Code, KnowledgeSource, Send, Stack, Times, Workspace } from '@citric/icons'
2
2
  import { IconButton } from '@citric/ui'
3
3
  import { MiniLogo } from '@stack-spot/portal-components/svg'
4
4
  import { listToClass } from '@stack-spot/portal-theme'
@@ -62,6 +62,11 @@ export const ButtonGroup = ({ features, onSend, onCancel, expanded, setExpanded,
62
62
  <Stack />
63
63
  </IconButton>
64
64
  )}
65
+ {features.editor && (
66
+ <IconButton aria-label={t.stack} title={t.stack} onClick={() => widget.set('panel', 'editor')}>
67
+ <Code />
68
+ </IconButton>
69
+ )}
65
70
  </div>
66
71
  <IconButton
67
72
  title={expanded ? t.collapse : t.expand}
@@ -1,5 +1,6 @@
1
1
  import { Times, TimesMini } from '@citric/icons'
2
2
  import { Badge, IconButton } from '@citric/ui'
3
+ import { loader } from '@monaco-editor/react'
3
4
  import { ColorPaletteName, listToClass } from '@stack-spot/portal-theme'
4
5
  import { useCallback, useMemo } from 'react'
5
6
  import { FadingOverflow } from '../../components/FadingOverflow'
@@ -26,7 +27,8 @@ export const InfoBar = () => {
26
27
  const currentStack = useCurrentChatState('stack')
27
28
  const currentWorkspace = useCurrentChatState('workspace')
28
29
  const currentKnowledgeSources = useCurrentChatState('knowledgeSources')
29
- const visible = !!(currentStack || currentWorkspace || currentKnowledgeSources?.length)
30
+ const currentSelection = useCurrentChatState('codeSelection')
31
+ const visible = !!(currentStack || currentWorkspace || currentKnowledgeSources?.length || currentSelection)
30
32
  const ksToRender = useMemo(() => currentKnowledgeSources?.map(ks => {
31
33
  const onDismiss = () => chat.set('knowledgeSources', currentKnowledgeSources.filter(({ id }) => id !== ks.id))
32
34
  return <li key={ks.id}><InfoBadge label={ks.label} dismiss={t.removeKS} color="teal" onDismiss={onDismiss} /></li>
@@ -36,6 +38,12 @@ export const InfoBar = () => {
36
38
  chat.set('knowledgeSources', [])
37
39
  chat.set('stack', undefined)
38
40
  chat.set('workspace', undefined)
41
+ removeCodeSelection()
42
+ }, [])
43
+
44
+ const removeCodeSelection = useCallback(() => {
45
+ const editor = loader.__getMonacoInstance()?.editor
46
+ editor?.getEditors()[0].setSelection({ startLineNumber: 0, endLineNumber: 0, endColumn: 0, startColumn: 0 })
39
47
  }, [])
40
48
 
41
49
  return (
@@ -45,6 +53,11 @@ export const InfoBar = () => {
45
53
  <IconButton aria-label={t.removeConfig} title={t.removeConfig} onClick={removeAll}><Times /></IconButton>
46
54
  <FadingOverflow className="list-overflow" scroll="arrows" enableHorizontalScrollWithVerticalWheel>
47
55
  <ul>
56
+ {currentSelection && (
57
+ <li>
58
+ <InfoBadge label={t.selected} dismiss={t.removeSelection} color="blue" onDismiss={removeCodeSelection} />
59
+ </li>
60
+ )}
48
61
  {currentStack && (
49
62
  <li>
50
63
  <InfoBadge label={currentStack.label} dismiss={t.removeStack} color="cyan" onDismiss={() => chat.set('stack', undefined)} />
@@ -15,6 +15,8 @@ const dictionary = {
15
15
  removeStack: 'Stop using the current stack',
16
16
  removeWorkspace: 'Stop using the current workspace',
17
17
  removeKS: 'Stop using this knowledge source',
18
+ selected: 'Selected',
19
+ removeSelection: 'Remove current code selection',
18
20
  },
19
21
  pt: {
20
22
  stack: 'Selecionar stack',
@@ -30,6 +32,8 @@ const dictionary = {
30
32
  removeStack: 'Parar de usar a stack atual',
31
33
  removeWorkspace: 'Parar de usar o workspace atual',
32
34
  removeKS: 'Parar de usar este knowledge source',
35
+ selected: 'Selecionado',
36
+ removeSelection: 'Desfazer seleção de código',
33
37
  },
34
38
  } satisfies Dictionary
35
39
 
@@ -28,7 +28,10 @@ export const MessageInput = ({ features }: Props) => {
28
28
  const onSend = useCallback(async () => {
29
29
  const message = chat.get('nextMessage')
30
30
  if (!message) return
31
- chat.pushMessage(ChatEntry.createUserEntry(message))
31
+ const code = chat.get('codeSelection')
32
+ const language = chat.get('codeLanguage')
33
+ const prompt = code ? `${message}\n\`\`\`${language}\n${code}\n\`\`\`` : message
34
+ chat.pushMessage(ChatEntry.createUserEntry(prompt, true))
32
35
  chat.set('nextMessage', '')
33
36
  setFocused(false)
34
37
  }, [chat])