@stack-spot/ai-chat-widget 1.7.2 → 1.8.2

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@stack-spot/ai-chat-widget",
3
- "version": "1.7.2",
4
- "date": "Thu Feb 13 2025 20:56:26 GMT+0000 (Coordinated Universal Time)",
3
+ "version": "1.8.2",
4
+ "date": "Thu Mar 13 2025 09:51:45 GMT-0300 (Brasilia Standard Time)",
5
5
  "dependencies": [
6
6
  {
7
7
  "name": "@stack-spot/app-metadata",
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Hook to manage keyboard shortcuts for the user's input history.
3
+ *
4
+ * This hook allows the user to navigate through the history of messages sent in a chat
5
+ * using the up arrow (`ArrowUp`) and down arrow (`ArrowDown`) keys.
6
+ */
7
+ export declare const useUserEntryHistoryShortcut: () => {
8
+ handleKeyDown: (event: React.KeyboardEvent<HTMLTextAreaElement>) => void;
9
+ handleKeyUp: (event: React.KeyboardEvent<HTMLTextAreaElement>) => void;
10
+ };
11
+ //# sourceMappingURL=chat-entry-history.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-entry-history.d.ts","sourceRoot":"","sources":["../../../src/views/MessageInput/chat-entry-history.ts"],"names":[],"mappings":"AAkCA;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B;2BA8BI,KAAK,CAAC,aAAa,CAAC,mBAAmB,CAAC;yBAU1C,KAAK,CAAC,aAAa,CAAC,mBAAmB,CAAC;CAOjF,CAAA"}
@@ -0,0 +1,71 @@
1
+ import { useCallback, useEffect, useRef } from 'react';
2
+ import { useCurrentChat } from '../../context/hooks.js';
3
+ const DEFAULT_POINTER = -1;
4
+ const useChatEntryHistory = () => {
5
+ const chat = useCurrentChat();
6
+ const historyPointer = useRef(DEFAULT_POINTER);
7
+ const messages = chat.getMessages();
8
+ useEffect(() => {
9
+ historyPointer.current = chat.getMessages().length;
10
+ }, [chat.id, messages]);
11
+ const navigateEntry = useCallback((startIndex, direction, inputValue) => {
12
+ const chatEntries = chat.getMessages() || [];
13
+ let pointer = startIndex + direction;
14
+ while (pointer > DEFAULT_POINTER && pointer < chatEntries.length && chatEntries[pointer]?.getValue().agentType !== 'user') {
15
+ pointer += direction;
16
+ }
17
+ if (pointer < DEFAULT_POINTER || pointer >= chatEntries.length + direction)
18
+ return inputValue;
19
+ historyPointer.current = pointer;
20
+ return chatEntries[pointer]?.getValue().content ?? inputValue;
21
+ }, [chat]);
22
+ const getPreviousUserEntry = useCallback((inputValue) => navigateEntry(historyPointer.current, -1, inputValue), [navigateEntry]);
23
+ const getNextUserEntry = useCallback((inputValue) => navigateEntry(historyPointer.current, +1, inputValue), [navigateEntry]);
24
+ return { getNextUserEntry, getPreviousUserEntry };
25
+ };
26
+ /**
27
+ * Hook to manage keyboard shortcuts for the user's input history.
28
+ *
29
+ * This hook allows the user to navigate through the history of messages sent in a chat
30
+ * using the up arrow (`ArrowUp`) and down arrow (`ArrowDown`) keys.
31
+ */
32
+ export const useUserEntryHistoryShortcut = () => {
33
+ const { getNextUserEntry, getPreviousUserEntry } = useChatEntryHistory();
34
+ const chat = useCurrentChat();
35
+ const userEntryRef = useRef('');
36
+ chat.onChange('nextMessage', (value) => {
37
+ if (value === '') {
38
+ userEntryRef.current = '';
39
+ }
40
+ });
41
+ const setNextMessageFromHistory = useCallback((event, getEntryHistory) => {
42
+ const textarea = event.target;
43
+ if (textarea.selectionStart !== 0)
44
+ return;
45
+ const entryHistory = getEntryHistory(userEntryRef.current);
46
+ if (entryHistory === chat.get('nextMessage'))
47
+ return;
48
+ chat.set('nextMessage', entryHistory);
49
+ requestAnimationFrame(() => {
50
+ textarea.selectionStart = 0;
51
+ textarea.selectionEnd = 0;
52
+ event.preventDefault();
53
+ event.stopPropagation();
54
+ });
55
+ }, [chat]);
56
+ const handleKeyDown = useCallback((event) => {
57
+ if (event.key === 'ArrowUp') {
58
+ setNextMessageFromHistory(event, getPreviousUserEntry);
59
+ }
60
+ if (event.key === 'ArrowDown') {
61
+ setNextMessageFromHistory(event, getNextUserEntry);
62
+ }
63
+ }, [getPreviousUserEntry, getNextUserEntry, setNextMessageFromHistory]);
64
+ const handleKeyUp = useCallback((event) => {
65
+ if (!event.key.startsWith('Arrow')) {
66
+ userEntryRef.current = chat.get('nextMessage') ?? '';
67
+ }
68
+ }, [chat]);
69
+ return { handleKeyDown, handleKeyUp };
70
+ };
71
+ //# sourceMappingURL=chat-entry-history.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-entry-history.js","sourceRoot":"","sources":["../../../src/views/MessageInput/chat-entry-history.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAEpD,MAAM,eAAe,GAAG,CAAC,CAAC,CAAA;AAE1B,MAAM,mBAAmB,GAAG,GAAG,EAAE;IAC/B,MAAM,IAAI,GAAG,cAAc,EAAE,CAAA;IAC7B,MAAM,cAAc,GAAG,MAAM,CAAC,eAAe,CAAC,CAAA;IAC9C,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,CAAA;IAEnC,SAAS,CAAC,GAAG,EAAE;QACb,cAAc,CAAC,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,MAAM,CAAA;IACpD,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAA;IAEvB,MAAM,aAAa,GAAG,WAAW,CAAC,CAAC,UAAkB,EAAE,SAAiB,EAAE,UAAkB,EAAE,EAAE;QAC9F,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,EAAE,IAAI,EAAE,CAAA;QAC5C,IAAI,OAAO,GAAG,UAAU,GAAG,SAAS,CAAA;QAEpC,OAAO,OAAO,GAAG,eAAe,IAAI,OAAO,GAAG,WAAW,CAAC,MAAM,IAAI,WAAW,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,CAAC,SAAS,KAAK,MAAM,EAAE,CAAC;YAC1H,OAAO,IAAI,SAAS,CAAA;QACtB,CAAC;QAED,IAAI,OAAO,GAAG,eAAe,IAAI,OAAO,IAAI,WAAW,CAAC,MAAM,GAAG,SAAS;YAAE,OAAO,UAAU,CAAA;QAE7F,cAAc,CAAC,OAAO,GAAG,OAAO,CAAA;QAChC,OAAO,WAAW,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,CAAC,OAAO,IAAI,UAAU,CAAA;IAC/D,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAA;IAEV,MAAM,oBAAoB,GAAG,WAAW,CAAC,CAAC,UAAkB,EAAE,EAAE,CAAC,aAAa,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAA;IACxI,MAAM,gBAAgB,GAAG,WAAW,CAAC,CAAC,UAAkB,EAAE,EAAE,CAAC,aAAa,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAA;IAEpI,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,CAAA;AACnD,CAAC,CAAA;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,GAAG,EAAE;IAC9C,MAAM,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,GAAG,mBAAmB,EAAE,CAAA;IACxE,MAAM,IAAI,GAAG,cAAc,EAAE,CAAA;IAC7B,MAAM,YAAY,GAAG,MAAM,CAAC,EAAE,CAAC,CAAA;IAE/B,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC,KAAK,EAAE,EAAE;QACrC,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;YACjB,YAAY,CAAC,OAAO,GAAG,EAAE,CAAA;QAC3B,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,MAAM,yBAAyB,GAAG,WAAW,CAC3C,CAAC,KAA+C,EAAE,eAAwC,EAAE,EAAE;QAC5F,MAAM,QAAQ,GAAG,KAAK,CAAC,MAA6B,CAAA;QACpD,IAAI,QAAQ,CAAC,cAAc,KAAK,CAAC;YAAE,OAAM;QAEzC,MAAM,YAAY,GAAG,eAAe,CAAC,YAAY,CAAC,OAAO,CAAC,CAAA;QAC1D,IAAI,YAAY,KAAK,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC;YAAE,OAAM;QAEpD,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,YAAY,CAAC,CAAA;QAErC,qBAAqB,CAAC,GAAG,EAAE;YACzB,QAAQ,CAAC,cAAc,GAAG,CAAC,CAAA;YAC3B,QAAQ,CAAC,YAAY,GAAG,CAAC,CAAA;YACzB,KAAK,CAAC,cAAc,EAAE,CAAA;YACtB,KAAK,CAAC,eAAe,EAAE,CAAA;QACzB,CAAC,CAAC,CAAA;IAEJ,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAA;IAEZ,MAAM,aAAa,GAAG,WAAW,CAAC,CAAC,KAA+C,EAAE,EAAE;QACpF,IAAI,KAAK,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;YAC5B,yBAAyB,CAAC,KAAK,EAAE,oBAAoB,CAAC,CAAA;QACxD,CAAC;QAED,IAAI,KAAK,CAAC,GAAG,KAAK,WAAW,EAAE,CAAC;YAC9B,yBAAyB,CAAC,KAAK,EAAE,gBAAgB,CAAC,CAAA;QACpD,CAAC;IACH,CAAC,EAAE,CAAC,oBAAoB,EAAE,gBAAgB,EAAE,yBAAyB,CAAC,CAAC,CAAA;IAEvE,MAAM,WAAW,GAAG,WAAW,CAAC,CAAC,KAA+C,EAAE,EAAE;QAClF,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YACnC,YAAY,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,EAAE,CAAA;QACtD,CAAC;IACH,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAA;IAEV,OAAO,EAAE,aAAa,EAAG,WAAW,EAAE,CAAA;AACxC,CAAC,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/views/MessageInput/index.tsx"],"names":[],"mappings":"AAgBA;;;;GAIG;AACH,eAAO,MAAM,YAAY,+CAsExB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/views/MessageInput/index.tsx"],"names":[],"mappings":"AAkBA;;;;GAIG;AACH,eAAO,MAAM,YAAY,+CA0ExB,CAAA"}
@@ -12,6 +12,7 @@ import { ButtonAgent } from './ButtonAgent.js';
12
12
  import { ButtonGroup } from './ButtonGroup.js';
13
13
  import { useMessageInputDictionary } from './dictionary.js';
14
14
  import { InfoBar } from './InfoBar.js';
15
+ import { useUserEntryHistoryShortcut } from './chat-entry-history.js';
15
16
  import { QuickCommandSelector } from './QuickCommandSelector.js';
16
17
  import { MAX_INPUT_HEIGHT, MessageInputBox, MIN_INPUT_HEIGHT } from './styled.js';
17
18
  /**
@@ -30,6 +31,7 @@ export const MessageInput = () => {
30
31
  const isMinimized = useWidgetState('isMinimized');
31
32
  const textAreaRef = useRef(null);
32
33
  const agentLabel = useCurrentChatState('agent')?.label ?? 'Stackspot AI';
34
+ const { handleKeyDown, handleKeyUp } = useUserEntryHistoryShortcut();
33
35
  const onSend = useCallback(async () => {
34
36
  const message = chat.get('nextMessage');
35
37
  if (!message)
@@ -46,12 +48,13 @@ export const MessageInput = () => {
46
48
  event.preventDefault();
47
49
  onSend();
48
50
  }
49
- }, [onSend]);
51
+ handleKeyDown(event);
52
+ }, [onSend, handleKeyDown]);
50
53
  useEffect(() => {
51
54
  if (!isLoading)
52
55
  textAreaRef.current?.focus();
53
56
  }, [isLoading]);
54
- return (_jsxs(MessageInputBox, { "aria-busy": isLoading, className: "message-input", children: [_jsx(ProgressBar, { visible: isLoading, shimmer: true }), _jsx(InfoBar, {}), _jsxs("div", { className: "wrapper-action", children: [_jsx(QuickCommandSelector, { inputRef: textAreaRef }), _jsx(AgentSelector, { inputRef: textAreaRef }), _jsxs("div", { className: listToClass(['action-box', focused && 'focused', isLoading && 'disabled']), children: [_jsx(ButtonAgent, {}), _jsx(AdaptiveTextArea, { ref: textAreaRef, disabled: isLoading, placeholder: interpolate(t.placeholder, agentLabel), onChange: e => chat.set('nextMessage', e.target.value), value: value, onFocus: () => setFocused(true), onBlur: () => setFocused(false), onKeyDown: onKeyDown, onIncreaseSize: () => setExpanded(false), onResetSize: () => !expansionLocked.current && setExpanded(true), maxHeight: isMinimized ? MIN_INPUT_HEIGHT : MAX_INPUT_HEIGHT }), _jsx(ButtonGroup, { onSend: onSend, onCancel: () => chat.abort(), expanded: expanded, isLoading: isLoading, setExpanded: (value) => {
57
+ return (_jsxs(MessageInputBox, { "aria-busy": isLoading, className: "message-input", children: [_jsx(ProgressBar, { visible: isLoading, shimmer: true }), _jsx(InfoBar, {}), _jsxs("div", { className: "wrapper-action", children: [_jsx(QuickCommandSelector, { inputRef: textAreaRef }), _jsx(AgentSelector, { inputRef: textAreaRef }), _jsxs("div", { className: listToClass(['action-box', focused && 'focused', isLoading && 'disabled']), children: [_jsx(ButtonAgent, {}), _jsx(AdaptiveTextArea, { ref: textAreaRef, disabled: isLoading, placeholder: interpolate(t.placeholder, agentLabel), onChange: e => chat.set('nextMessage', e.target.value), value: value, onFocus: () => setFocused(true), onBlur: () => setFocused(false), onKeyDown: onKeyDown, onKeyUp: handleKeyUp, onIncreaseSize: () => setExpanded(false), onResetSize: () => !expansionLocked.current && setExpanded(true), maxHeight: isMinimized ? MIN_INPUT_HEIGHT : MAX_INPUT_HEIGHT }), _jsx(ButtonGroup, { onSend: onSend, onCancel: () => chat.abort(), expanded: expanded, isLoading: isLoading, setExpanded: (value) => {
55
58
  setExpanded(value);
56
59
  expansionLocked.current = expanded;
57
60
  } })] })] })] }));
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/views/MessageInput/index.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/views/MessageInput/index.tsx"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stack-spot/ai-chat-widget",
3
- "version": "1.7.2",
3
+ "version": "1.8.2",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@stack-spot/ai-chat-widget",
3
- "version": "1.7.2",
4
- "date": "Thu Feb 13 2025 20:56:26 GMT+0000 (Coordinated Universal Time)",
3
+ "version": "1.8.2",
4
+ "date": "Thu Mar 13 2025 09:51:45 GMT-0300 (Brasilia Standard Time)",
5
5
  "dependencies": [
6
6
  {
7
7
  "name": "@stack-spot/app-metadata",
@@ -0,0 +1,88 @@
1
+ import { useCallback, useEffect, useRef } from 'react'
2
+ import { useCurrentChat } from '../../context/hooks'
3
+
4
+ const DEFAULT_POINTER = -1
5
+
6
+ const useChatEntryHistory = () => {
7
+ const chat = useCurrentChat()
8
+ const historyPointer = useRef(DEFAULT_POINTER)
9
+ const messages = chat.getMessages()
10
+
11
+ useEffect(() => {
12
+ historyPointer.current = chat.getMessages().length
13
+ }, [chat.id, messages])
14
+
15
+ const navigateEntry = useCallback((startIndex: number, direction: 1 | -1, inputValue: string) => {
16
+ const chatEntries = chat.getMessages() || []
17
+ let pointer = startIndex + direction
18
+
19
+ while (pointer > DEFAULT_POINTER && pointer < chatEntries.length && chatEntries[pointer]?.getValue().agentType !== 'user') {
20
+ pointer += direction
21
+ }
22
+
23
+ if (pointer < DEFAULT_POINTER || pointer >= chatEntries.length + direction) return inputValue
24
+
25
+ historyPointer.current = pointer
26
+ return chatEntries[pointer]?.getValue().content ?? inputValue
27
+ }, [chat])
28
+
29
+ const getPreviousUserEntry = useCallback((inputValue: string) => navigateEntry(historyPointer.current, -1, inputValue), [navigateEntry])
30
+ const getNextUserEntry = useCallback((inputValue: string) => navigateEntry(historyPointer.current, +1, inputValue), [navigateEntry])
31
+
32
+ return { getNextUserEntry, getPreviousUserEntry }
33
+ }
34
+
35
+ /**
36
+ * Hook to manage keyboard shortcuts for the user's input history.
37
+ *
38
+ * This hook allows the user to navigate through the history of messages sent in a chat
39
+ * using the up arrow (`ArrowUp`) and down arrow (`ArrowDown`) keys.
40
+ */
41
+ export const useUserEntryHistoryShortcut = () => {
42
+ const { getNextUserEntry, getPreviousUserEntry } = useChatEntryHistory()
43
+ const chat = useCurrentChat()
44
+ const userEntryRef = useRef('')
45
+
46
+ chat.onChange('nextMessage', (value) => {
47
+ if (value === '') {
48
+ userEntryRef.current = ''
49
+ }
50
+ })
51
+
52
+ const setNextMessageFromHistory = useCallback(
53
+ (event: React.KeyboardEvent<HTMLTextAreaElement>, getEntryHistory: typeof getNextUserEntry) => {
54
+ const textarea = event.target as HTMLTextAreaElement
55
+ if (textarea.selectionStart !== 0) return
56
+
57
+ const entryHistory = getEntryHistory(userEntryRef.current)
58
+ if (entryHistory === chat.get('nextMessage')) return
59
+
60
+ chat.set('nextMessage', entryHistory)
61
+
62
+ requestAnimationFrame(() => {
63
+ textarea.selectionStart = 0
64
+ textarea.selectionEnd = 0
65
+ event.preventDefault()
66
+ event.stopPropagation()
67
+ })
68
+
69
+ }, [chat])
70
+
71
+ const handleKeyDown = useCallback((event: React.KeyboardEvent<HTMLTextAreaElement>) => {
72
+ if (event.key === 'ArrowUp') {
73
+ setNextMessageFromHistory(event, getPreviousUserEntry)
74
+ }
75
+
76
+ if (event.key === 'ArrowDown') {
77
+ setNextMessageFromHistory(event, getNextUserEntry)
78
+ }
79
+ }, [getPreviousUserEntry, getNextUserEntry, setNextMessageFromHistory])
80
+
81
+ const handleKeyUp = useCallback((event: React.KeyboardEvent<HTMLTextAreaElement>) => {
82
+ if (!event.key.startsWith('Arrow')) {
83
+ userEntryRef.current = chat.get('nextMessage') ?? ''
84
+ }
85
+ }, [chat])
86
+
87
+ return { handleKeyDown, handleKeyUp }
88
+ }
@@ -11,6 +11,8 @@ import { ButtonAgent } from './ButtonAgent'
11
11
  import { ButtonGroup } from './ButtonGroup'
12
12
  import { useMessageInputDictionary } from './dictionary'
13
13
  import { InfoBar } from './InfoBar'
14
+
15
+ import { useUserEntryHistoryShortcut } from './chat-entry-history'
14
16
  import { QuickCommandSelector } from './QuickCommandSelector'
15
17
  import { MAX_INPUT_HEIGHT, MessageInputBox, MIN_INPUT_HEIGHT } from './styled'
16
18
 
@@ -30,6 +32,7 @@ export const MessageInput = () => {
30
32
  const isMinimized = useWidgetState('isMinimized')
31
33
  const textAreaRef = useRef<HTMLTextAreaElement>(null)
32
34
  const agentLabel = useCurrentChatState('agent')?.label ?? 'Stackspot AI'
35
+ const { handleKeyDown, handleKeyUp } = useUserEntryHistoryShortcut()
33
36
 
34
37
  const onSend = useCallback(async () => {
35
38
  const message = chat.get('nextMessage')
@@ -47,7 +50,9 @@ export const MessageInput = () => {
47
50
  event.preventDefault()
48
51
  onSend()
49
52
  }
50
- }, [onSend])
53
+
54
+ handleKeyDown(event)
55
+ }, [onSend, handleKeyDown])
51
56
 
52
57
  useEffect(() => {
53
58
  if (!isLoading) textAreaRef.current?.focus()
@@ -71,6 +76,7 @@ export const MessageInput = () => {
71
76
  onFocus={() => setFocused(true)}
72
77
  onBlur={() => setFocused(false)}
73
78
  onKeyDown={onKeyDown}
79
+ onKeyUp={handleKeyUp}
74
80
  onIncreaseSize={() => setExpanded(false)}
75
81
  onResetSize={() => !expansionLocked.current && setExpanded(true)}
76
82
  maxHeight={isMinimized ? MIN_INPUT_HEIGHT : MAX_INPUT_HEIGHT}