@asgard-js/react 0.0.36 → 0.0.37-canary.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.
Files changed (129) hide show
  1. package/dist/components/chatbot/chatbot-footer/chatbot-footer.d.ts.map +1 -1
  2. package/dist/context/asgard-service-context.d.ts.map +1 -1
  3. package/dist/context/asgard-theme-context.d.ts.map +1 -1
  4. package/dist/hooks/use-react-markdown-renderer.d.ts.map +1 -1
  5. package/dist/index.js +18160 -18881
  6. package/dist/style.css +1 -1
  7. package/package.json +2 -2
  8. package/.babelrc +0 -12
  9. package/dist/utils/color-utils.d.ts +0 -18
  10. package/dist/utils/color-utils.d.ts.map +0 -1
  11. package/eslint.config.cjs +0 -12
  12. package/src/components/chatbot/chatbot-body/chatbot-body.module.scss +0 -13
  13. package/src/components/chatbot/chatbot-body/chatbot-body.tsx +0 -45
  14. package/src/components/chatbot/chatbot-body/conversation-message-renderer.tsx +0 -55
  15. package/src/components/chatbot/chatbot-body/index.ts +0 -1
  16. package/src/components/chatbot/chatbot-container/chatbot-container.module.scss +0 -41
  17. package/src/components/chatbot/chatbot-container/chatbot-container.tsx +0 -49
  18. package/src/components/chatbot/chatbot-container/chatbot-full-screen-container.tsx +0 -54
  19. package/src/components/chatbot/chatbot-footer/chatbot-footer.module.scss +0 -67
  20. package/src/components/chatbot/chatbot-footer/chatbot-footer.tsx +0 -144
  21. package/src/components/chatbot/chatbot-footer/index.ts +0 -1
  22. package/src/components/chatbot/chatbot-footer/speech-input-button.tsx +0 -132
  23. package/src/components/chatbot/chatbot-header/chatbot-header.module.scss +0 -48
  24. package/src/components/chatbot/chatbot-header/chatbot-header.tsx +0 -98
  25. package/src/components/chatbot/chatbot-header/index.ts +0 -1
  26. package/src/components/chatbot/chatbot.spec.tsx +0 -8
  27. package/src/components/chatbot/chatbot.tsx +0 -118
  28. package/src/components/chatbot/profile-icon.tsx +0 -26
  29. package/src/components/index.ts +0 -2
  30. package/src/components/templates/avatar/avatar.module.scss +0 -6
  31. package/src/components/templates/avatar/avatar.tsx +0 -28
  32. package/src/components/templates/avatar/index.ts +0 -1
  33. package/src/components/templates/button-template/button-template.module.scss +0 -0
  34. package/src/components/templates/button-template/button-template.tsx +0 -45
  35. package/src/components/templates/button-template/card.module.scss +0 -58
  36. package/src/components/templates/button-template/card.spec.tsx +0 -213
  37. package/src/components/templates/button-template/card.tsx +0 -123
  38. package/src/components/templates/button-template/index.ts +0 -1
  39. package/src/components/templates/carousel-template/carousel-template.module.scss +0 -15
  40. package/src/components/templates/carousel-template/carousel-template.tsx +0 -49
  41. package/src/components/templates/carousel-template/index.ts +0 -1
  42. package/src/components/templates/chart-template/chart-template.module.scss +0 -52
  43. package/src/components/templates/chart-template/chart-template.tsx +0 -75
  44. package/src/components/templates/chart-template/index.ts +0 -1
  45. package/src/components/templates/hint-template/hint-template.module.scss +0 -39
  46. package/src/components/templates/hint-template/hint-template.tsx +0 -71
  47. package/src/components/templates/hint-template/index.ts +0 -1
  48. package/src/components/templates/image-template/image-template.module.scss +0 -67
  49. package/src/components/templates/image-template/image-template.tsx +0 -58
  50. package/src/components/templates/image-template/index.ts +0 -1
  51. package/src/components/templates/index.ts +0 -10
  52. package/src/components/templates/quick-replies/index.ts +0 -1
  53. package/src/components/templates/quick-replies/quick-replies.module.scss +0 -16
  54. package/src/components/templates/quick-replies/quick-replies.tsx +0 -44
  55. package/src/components/templates/template-box/index.ts +0 -2
  56. package/src/components/templates/template-box/template-box-content.module.scss +0 -13
  57. package/src/components/templates/template-box/template-box-content.tsx +0 -30
  58. package/src/components/templates/template-box/template-box.module.scss +0 -19
  59. package/src/components/templates/template-box/template-box.tsx +0 -48
  60. package/src/components/templates/text-template/bot-typing-box.tsx +0 -81
  61. package/src/components/templates/text-template/bot-typing-placeholder.tsx +0 -28
  62. package/src/components/templates/text-template/index.ts +0 -3
  63. package/src/components/templates/text-template/text-template.module.scss +0 -131
  64. package/src/components/templates/text-template/text-template.tsx +0 -90
  65. package/src/components/templates/text-template/use-react-markdown-renderer.spec.tsx +0 -758
  66. package/src/components/templates/time/index.ts +0 -1
  67. package/src/components/templates/time/time.module.scss +0 -6
  68. package/src/components/templates/time/time.tsx +0 -34
  69. package/src/context/asgard-app-initialization-context.tsx +0 -154
  70. package/src/context/asgard-service-context.tsx +0 -148
  71. package/src/context/asgard-template-context.tsx +0 -83
  72. package/src/context/asgard-theme-context.tsx +0 -417
  73. package/src/context/index.ts +0 -4
  74. package/src/hooks/index.ts +0 -11
  75. package/src/hooks/use-asgard-service-client.ts +0 -68
  76. package/src/hooks/use-channel.ts +0 -154
  77. package/src/hooks/use-debounce.ts +0 -18
  78. package/src/hooks/use-deep-compare-memo.ts +0 -19
  79. package/src/hooks/use-is-on-screen-keyboard-open.ts +0 -43
  80. package/src/hooks/use-on-screen-keyboard-scroll-fix.ts +0 -15
  81. package/src/hooks/use-prevent-over-scrolling.ts +0 -77
  82. package/src/hooks/use-react-markdown-renderer.tsx +0 -272
  83. package/src/hooks/use-resize-observer.tsx +0 -27
  84. package/src/hooks/use-update-vh.ts +0 -30
  85. package/src/hooks/use-viewport-size.ts +0 -51
  86. package/src/icons/add_a_photo.svg +0 -3
  87. package/src/icons/bot.svg +0 -14
  88. package/src/icons/close.svg +0 -3
  89. package/src/icons/distance.svg +0 -3
  90. package/src/icons/mic.svg +0 -3
  91. package/src/icons/photo_library.svg +0 -3
  92. package/src/icons/profile.svg +0 -28
  93. package/src/icons/refresh.svg +0 -3
  94. package/src/icons/send.svg +0 -3
  95. package/src/icons/stop.svg +0 -22
  96. package/src/icons/volume_up.svg +0 -3
  97. package/src/index.ts +0 -4
  98. package/src/models/bot-provider.ts +0 -108
  99. package/src/styles/_index.scss +0 -1
  100. package/src/styles/_styles.scss +0 -11
  101. package/src/styles/colors/_colors.scss +0 -10
  102. package/src/styles/colors/_index.scss +0 -1
  103. package/src/styles/colors/_variables.scss +0 -72
  104. package/src/styles/palette/_index.scss +0 -1
  105. package/src/styles/palette/_palette.scss +0 -42
  106. package/src/styles/palette/_variables.scss +0 -40
  107. package/src/styles/radius/_index.scss +0 -1
  108. package/src/styles/radius/_radius.scss +0 -8
  109. package/src/styles/radius/_variables.scss +0 -12
  110. package/src/styles/spacing/_index.scss +0 -1
  111. package/src/styles/spacing/_spacing.scss +0 -8
  112. package/src/styles/spacing/_variables.scss +0 -13
  113. package/src/styles/utils/_index.scss +0 -1
  114. package/src/styles/utils/_map.scss +0 -22
  115. package/src/test-setup.ts +0 -1
  116. package/src/utils/color-utils.ts +0 -38
  117. package/src/utils/deep-merge.ts +0 -26
  118. package/src/utils/extractors.ts +0 -20
  119. package/src/utils/format-time.ts +0 -8
  120. package/src/utils/index.ts +0 -1
  121. package/src/utils/is.ts +0 -72
  122. package/src/utils/selectors.ts +0 -7
  123. package/src/utils/uri-validation.spec.ts +0 -208
  124. package/src/utils/uri-validation.ts +0 -103
  125. package/tsconfig.json +0 -16
  126. package/tsconfig.lib.json +0 -63
  127. package/tsconfig.spec.json +0 -36
  128. package/tsconfig.tsbuildinfo +0 -1
  129. package/vite.config.ts +0 -63
@@ -1,417 +0,0 @@
1
- import {
2
- createContext,
3
- CSSProperties,
4
- PropsWithChildren,
5
- ReactNode,
6
- useContext,
7
- useEffect,
8
- useMemo,
9
- useCallback,
10
- } from 'react';
11
- import { deepMerge } from '../utils/deep-merge';
12
- import { addTransparency, darkenColor } from '../utils/color-utils';
13
- import {
14
- useAsgardAppInitializationContext,
15
- Annotations,
16
- } from './asgard-app-initialization-context';
17
-
18
- export interface AsgardThemeContextValue {
19
- chatbot: Pick<
20
- CSSProperties,
21
- | 'width'
22
- | 'height'
23
- | 'maxWidth'
24
- | 'minWidth'
25
- | 'maxHeight'
26
- | 'minHeight'
27
- | 'backgroundColor'
28
- | 'borderColor'
29
- | 'borderRadius'
30
- > & {
31
- contentMaxWidth?: CSSProperties['maxWidth'];
32
- backgroundColor?: CSSProperties['backgroundColor'];
33
- borderColor?: CSSProperties['borderColor'];
34
- inactiveColor?: CSSProperties['color'];
35
- primaryComponent?: {
36
- mainColor?: CSSProperties['color'];
37
- secondaryColor?: CSSProperties['color'];
38
- };
39
- style?: CSSProperties;
40
- header?: Partial<{
41
- style: CSSProperties;
42
- title: {
43
- style: CSSProperties;
44
- };
45
- actionButton?: {
46
- style: CSSProperties;
47
- };
48
- }>;
49
- body?: Partial<{
50
- style: CSSProperties;
51
- }>;
52
- footer?: Partial<{
53
- style: CSSProperties;
54
- textArea: {
55
- style: CSSProperties;
56
- '::placeholder': CSSProperties;
57
- };
58
- submitButton: {
59
- style: CSSProperties;
60
- };
61
- speechInputButton: {
62
- style: CSSProperties;
63
- };
64
- }>;
65
- };
66
- botMessage: Pick<CSSProperties, 'color' | 'backgroundColor'>;
67
- userMessage: Pick<CSSProperties, 'color' | 'backgroundColor'>;
68
- template?: Partial<{
69
- /**
70
- * first level for common/shared properties.
71
- * Check MessageTemplate type for more details (packages/core/src/types/sse-response.ts).
72
- */
73
- quickReplies?: Partial<{
74
- style: CSSProperties;
75
- button: {
76
- style: CSSProperties;
77
- };
78
- }>;
79
- time?: Partial<{
80
- style: CSSProperties;
81
- }>;
82
- /**
83
- * TBD: Fill the necessary properties based on the requirements.
84
- */
85
- TextMessageTemplate: Partial<{ style: CSSProperties }>;
86
- /**
87
- * TBD: Fill the necessary properties based on the requirements.
88
- */
89
- HintMessageTemplate: Partial<{ style: CSSProperties }>;
90
- /**
91
- * TBD: Fill the necessary properties based on the requirements.
92
- */
93
- ImageMessageTemplate: Partial<{ style: CSSProperties }>;
94
- /**
95
- * TBD: Fill the necessary properties based on the requirements.
96
- */
97
- VideoMessageTemplate: Partial<{ style: CSSProperties }>;
98
- /**
99
- * TBD: Fill the necessary properties based on the requirements.
100
- */
101
- AudioMessageTemplate: Partial<{ style: CSSProperties }>;
102
- /**
103
- * TBD: Fill the necessary properties based on the requirements.
104
- */
105
- LocationMessageTemplate: Partial<{ style: CSSProperties }>;
106
- /**
107
- * TBD: Fill the necessary properties based on the requirements.
108
- */
109
- ChartMessageTemplate: Partial<{ style: CSSProperties }>;
110
- /**
111
- * TBD: Fill the necessary properties based on the requirements.
112
- */
113
- ButtonMessageTemplate: Partial<{
114
- style: CSSProperties;
115
- button?: {
116
- style: CSSProperties;
117
- };
118
- }>;
119
- /**
120
- * TBD: Fill the necessary properties based on the requirements.
121
- */
122
- CarouselMessageTemplate: Partial<{
123
- style: CSSProperties;
124
- card: {
125
- style: CSSProperties;
126
- button?: {
127
- style: CSSProperties;
128
- };
129
- };
130
- }>;
131
- }>;
132
- }
133
-
134
- export const defaultAsgardThemeContextValue: AsgardThemeContextValue = {
135
- chatbot: {
136
- width: '375px',
137
- height: '640px',
138
- backgroundColor: 'var(--asg-color-bg)',
139
- borderColor: 'var(--asg-color-border)',
140
- borderRadius: 'var(--asg-radius-md)',
141
- contentMaxWidth: '1200px',
142
- style: {},
143
- header: {
144
- style: {},
145
- title: {
146
- style: {},
147
- },
148
- actionButton: {
149
- style: {},
150
- },
151
- },
152
- body: {
153
- style: {},
154
- },
155
- footer: {
156
- style: {},
157
- textArea: {
158
- style: {},
159
- '::placeholder': {
160
- color: 'var(--asg-color-text-placeholder)',
161
- },
162
- },
163
- submitButton: {
164
- style: {},
165
- },
166
- speechInputButton: {
167
- style: {},
168
- },
169
- },
170
- },
171
- botMessage: {
172
- color: 'var(--asg-color-text)',
173
- backgroundColor: 'var(--asg-color-secondary)',
174
- },
175
- userMessage: {
176
- color: 'var(--asg-color-text)',
177
- backgroundColor: 'var(--asg-color-primary)',
178
- },
179
- template: {
180
- quickReplies: {
181
- style: {},
182
- button: {
183
- style: {},
184
- },
185
- },
186
- time: {
187
- style: {},
188
- },
189
- TextMessageTemplate: {
190
- style: {},
191
- },
192
- HintMessageTemplate: {
193
- style: {},
194
- },
195
- ImageMessageTemplate: {
196
- style: {},
197
- },
198
- VideoMessageTemplate: {
199
- style: {},
200
- },
201
- AudioMessageTemplate: {
202
- style: {},
203
- },
204
- LocationMessageTemplate: {
205
- style: {},
206
- },
207
- ChartMessageTemplate: {
208
- style: {},
209
- },
210
- ButtonMessageTemplate: {
211
- style: {},
212
- button: {
213
- style: {
214
- border: '1px solid var(--asg-color-border)',
215
- },
216
- },
217
- },
218
- CarouselMessageTemplate: {
219
- style: {},
220
- card: {
221
- style: {},
222
- button: {
223
- style: {
224
- border: '1px solid var(--asg-color-border)',
225
- },
226
- },
227
- },
228
- },
229
- },
230
- };
231
-
232
- export const AsgardThemeContext = createContext<AsgardThemeContextValue>(
233
- defaultAsgardThemeContextValue
234
- );
235
-
236
- export function AsgardThemeContextProvider(
237
- props: PropsWithChildren<{
238
- theme?: Partial<AsgardThemeContextValue>;
239
- }>
240
- ): ReactNode {
241
- const { children, theme = {} } = props;
242
- const {
243
- data: { annotations },
244
- } = useAsgardAppInitializationContext();
245
-
246
- const deepMergeTheme = useCallback(
247
- function () {
248
- /**
249
- * Orders of theme (high to low):
250
- * 1. Theme from props
251
- * 2. Theme from annotations
252
- * 3. Default theme
253
- */
254
-
255
- const themeFromAnnotations: Annotations['embedConfig']['theme'] =
256
- annotations?.embedConfig?.theme ?? {
257
- chatbot: {},
258
- botMessage: {},
259
- userMessage: {},
260
- };
261
-
262
- const tempTheme = deepMerge(defaultAsgardThemeContextValue as unknown as Record<string, unknown>, {
263
- chatbot: {
264
- backgroundColor: themeFromAnnotations.chatbot?.backgroundColor,
265
- borderColor: themeFromAnnotations.chatbot?.borderColor,
266
- header: {
267
- style: {
268
- borderBottomColor: themeFromAnnotations.chatbot?.borderColor,
269
- },
270
- title: {
271
- style: {
272
- color:
273
- themeFromAnnotations.chatbot?.primaryComponent
274
- ?.secondaryColor, // Title text color
275
- },
276
- },
277
- actionButton: {
278
- style: {
279
- color: themeFromAnnotations.chatbot?.inactiveColor,
280
- },
281
- },
282
- },
283
- body: {
284
- style: {
285
- // Time/timestamp text color
286
- color: themeFromAnnotations.chatbot?.inactiveColor,
287
- },
288
- },
289
- footer: {
290
- style: {
291
- borderTopColor: themeFromAnnotations.chatbot?.borderColor,
292
- },
293
- textArea: {
294
- style: {
295
- color: themeFromAnnotations.chatbot?.inactiveColor,
296
- backgroundColor: themeFromAnnotations.chatbot?.backgroundColor,
297
- },
298
- '::placeholder': {
299
- color: themeFromAnnotations.chatbot?.inactiveColor,
300
- },
301
- },
302
- submitButton: {
303
- style: {
304
- color:
305
- themeFromAnnotations.chatbot?.primaryComponent
306
- ?.secondaryColor,
307
- },
308
- },
309
- speechInputButton: {
310
- style: {
311
- color:
312
- themeFromAnnotations.chatbot?.primaryComponent
313
- ?.secondaryColor,
314
- },
315
- },
316
- },
317
- },
318
- botMessage: {
319
- backgroundColor: themeFromAnnotations.botMessage?.backgroundColor, // #585858
320
- color: themeFromAnnotations.botMessage?.color,
321
- },
322
- userMessage: {
323
- backgroundColor: themeFromAnnotations.userMessage?.backgroundColor,
324
- color: themeFromAnnotations.userMessage?.color,
325
- },
326
- template: {
327
- quickReplies: {
328
- button: {
329
- style: {
330
- color:
331
- themeFromAnnotations.chatbot?.primaryComponent
332
- ?.secondaryColor, // Button text (#FFFFFF)
333
- borderColor: themeFromAnnotations.chatbot?.borderColor,
334
- backgroundColor: themeFromAnnotations.botMessage
335
- ?.backgroundColor
336
- ? addTransparency(themeFromAnnotations.botMessage.backgroundColor, 0.2)
337
- : undefined,
338
- },
339
- },
340
- },
341
- time: {
342
- style: {
343
- color: themeFromAnnotations.chatbot?.inactiveColor,
344
- },
345
- },
346
- TextMessageTemplate: {
347
- style: {
348
- // For unset messages
349
- color:
350
- themeFromAnnotations.chatbot?.primaryComponent?.secondaryColor,
351
- backgroundColor: themeFromAnnotations.botMessage?.backgroundColor
352
- ? addTransparency(themeFromAnnotations.botMessage.backgroundColor, 0.2)
353
- : undefined,
354
- },
355
- },
356
- ButtonMessageTemplate: {
357
- button: {
358
- style: {
359
- borderColor: themeFromAnnotations.chatbot?.borderColor,
360
- backgroundColor:
361
- themeFromAnnotations.chatbot?.primaryComponent?.mainColor,
362
- color:
363
- themeFromAnnotations.chatbot?.primaryComponent
364
- ?.secondaryColor,
365
- },
366
- },
367
- },
368
- CarouselMessageTemplate: {
369
- card: {
370
- style: {
371
- backgroundColor:
372
- themeFromAnnotations.botMessage
373
- ?.carouselButtonBackgroundColor,
374
- },
375
- button: {
376
- style: {
377
- borderColor: themeFromAnnotations.chatbot?.borderColor,
378
- backgroundColor:
379
- themeFromAnnotations.chatbot?.primaryComponent?.mainColor,
380
- color:
381
- themeFromAnnotations.chatbot?.primaryComponent
382
- ?.secondaryColor,
383
- },
384
- },
385
- },
386
- },
387
- },
388
- });
389
-
390
- return deepMerge(tempTheme, theme);
391
- },
392
- [theme, annotations?.embedConfig?.theme]
393
- );
394
-
395
- const value = useMemo(() => deepMergeTheme(), [deepMergeTheme]);
396
-
397
- // 設置 CSS 自定義屬性
398
- useEffect(() => {
399
- const botMessageBgColor = annotations?.embedConfig?.theme?.botMessage?.backgroundColor;
400
- if (botMessageBgColor) {
401
- document.documentElement.style.setProperty(
402
- '--bot-message-hyperlink-color',
403
- darkenColor(botMessageBgColor, 0.2)
404
- );
405
- }
406
- }, [annotations?.embedConfig?.theme?.botMessage?.backgroundColor]);
407
-
408
- return (
409
- <AsgardThemeContext.Provider value={value}>
410
- {children}
411
- </AsgardThemeContext.Provider>
412
- );
413
- }
414
-
415
- export function useAsgardThemeContext(): AsgardThemeContextValue {
416
- return useContext(AsgardThemeContext);
417
- }
@@ -1,4 +0,0 @@
1
- export * from './asgard-service-context';
2
- export * from './asgard-template-context';
3
- export * from './asgard-theme-context';
4
- export * from './asgard-app-initialization-context';
@@ -1,11 +0,0 @@
1
- export * from './use-asgard-service-client';
2
- export * from './use-channel';
3
- export * from './use-debounce';
4
- export * from './use-viewport-size';
5
- export * from './use-is-on-screen-keyboard-open';
6
- export * from './use-on-screen-keyboard-scroll-fix';
7
- export * from './use-prevent-over-scrolling';
8
- export * from './use-update-vh';
9
- export * from './use-resize-observer';
10
- export * from './use-deep-compare-memo';
11
- export * from './use-react-markdown-renderer';
@@ -1,68 +0,0 @@
1
- import { ClientConfig, AsgardServiceClient, EventType } from '@asgard-js/core';
2
- import { useEffect, useRef } from 'react';
3
-
4
- interface UseAsgardServiceClientProps {
5
- config: ClientConfig;
6
- }
7
-
8
- export function useAsgardServiceClient(
9
- props: UseAsgardServiceClientProps
10
- ): AsgardServiceClient | null {
11
- const { config } = props;
12
-
13
- const { onRunInit, onProcess, onMessage, onToolCall, onRunDone, onRunError } =
14
- config;
15
-
16
- const clientRef = useRef<AsgardServiceClient | null>(null);
17
-
18
- if (!clientRef.current) {
19
- clientRef.current = new AsgardServiceClient(config);
20
- }
21
-
22
- useEffect(() => {
23
- return (): void => {
24
- if (clientRef.current) {
25
- clientRef.current.close();
26
- clientRef.current = null;
27
- }
28
- };
29
- }, []);
30
-
31
- useEffect(() => {
32
- if (!clientRef.current || !onRunInit) return;
33
-
34
- clientRef.current.on(EventType.INIT, onRunInit);
35
- }, [onRunInit]);
36
-
37
- useEffect(() => {
38
- if (!clientRef.current || !onProcess) return;
39
-
40
- clientRef.current.on(EventType.PROCESS, onProcess);
41
- }, [onProcess]);
42
-
43
- useEffect(() => {
44
- if (!clientRef.current || !onMessage) return;
45
-
46
- clientRef.current.on(EventType.MESSAGE, onMessage);
47
- }, [onMessage]);
48
-
49
- useEffect(() => {
50
- if (!clientRef.current || !onToolCall) return;
51
-
52
- clientRef.current.on(EventType.TOOL_CALL, onToolCall);
53
- }, [onToolCall]);
54
-
55
- useEffect(() => {
56
- if (!clientRef.current || !onRunDone) return;
57
-
58
- clientRef.current.on(EventType.DONE, onRunDone);
59
- }, [onRunDone]);
60
-
61
- useEffect(() => {
62
- if (!clientRef.current || !onRunError) return;
63
-
64
- clientRef.current.on(EventType.ERROR, onRunError);
65
- }, [onRunError]);
66
-
67
- return clientRef.current;
68
- }
@@ -1,154 +0,0 @@
1
- import {
2
- AsgardServiceClient,
3
- Channel,
4
- ChannelStates,
5
- Conversation,
6
- ConversationMessage,
7
- EventType,
8
- FetchSsePayload,
9
- SseResponse,
10
- } from '@asgard-js/core';
11
- import { useCallback, useEffect, useMemo, useState } from 'react';
12
-
13
- export interface UseChannelProps {
14
- defaultIsOpen?: boolean;
15
- resetPayload?: Pick<FetchSsePayload, 'text'> & Partial<Pick<FetchSsePayload, 'payload'>>;
16
- client: AsgardServiceClient | null;
17
- customChannelId: string;
18
- customMessageId?: string;
19
- initMessages?: ConversationMessage[];
20
- onSseMessage?: (
21
- response: SseResponse<EventType>,
22
- context: {
23
- conversation: Conversation | null;
24
- }
25
- ) => void;
26
- }
27
-
28
- export interface UseChannelReturn {
29
- isOpen: boolean;
30
- isResetting: boolean;
31
- isConnecting: boolean;
32
- conversation: Conversation | null;
33
- sendMessage?: (payload: Pick<FetchSsePayload, 'text'> & Partial<Pick<FetchSsePayload, 'payload'>>) => void;
34
- resetChannel?: (payload?: Pick<FetchSsePayload, 'text'> & Partial<Pick<FetchSsePayload, 'payload'>>) => void;
35
- closeChannel?: () => void;
36
- }
37
-
38
- export function useChannel(props: UseChannelProps): UseChannelReturn {
39
- const {
40
- client,
41
- defaultIsOpen,
42
- resetPayload,
43
- customChannelId,
44
- customMessageId,
45
- initMessages,
46
- onSseMessage,
47
- } = props;
48
-
49
- if (!client) {
50
- throw new Error('Client instance is required');
51
- }
52
-
53
- if (!customChannelId) {
54
- throw new Error('Custom channel id is required');
55
- }
56
-
57
- const [channel, setChannel] = useState<Channel | null>(null);
58
- const [isOpen, setIsOpen] = useState(defaultIsOpen ?? true);
59
- const [isResetting, setIsResetting] = useState(false);
60
- const [isConnecting, setIsConnecting] = useState(false);
61
- const [conversation, setConversation] = useState<Conversation | null>(null);
62
-
63
- const resetChannel = useCallback(
64
- async (payload?: Pick<FetchSsePayload, 'text'> & Partial<Pick<FetchSsePayload, 'payload'>>) => {
65
- const conversation = new Conversation({
66
- messages: new Map(
67
- initMessages?.map((message) => [message.messageId, message])
68
- ),
69
- });
70
-
71
- setIsResetting(true);
72
- setIsConnecting(true);
73
- setConversation(conversation);
74
-
75
- const channel = await Channel.reset(
76
- {
77
- client,
78
- customChannelId,
79
- customMessageId,
80
- conversation,
81
- statesObserver: (states: ChannelStates): void => {
82
- setIsConnecting(states.isConnecting);
83
- setConversation(states.conversation);
84
- },
85
- },
86
- payload,
87
- {
88
- onSseCompleted() {
89
- setIsResetting(false);
90
- },
91
- onSseError() {
92
- setIsResetting(false);
93
- },
94
- onSseMessage(response: SseResponse<EventType>) {
95
- onSseMessage?.(response, {
96
- conversation,
97
- });
98
- },
99
- }
100
- );
101
-
102
- setIsOpen(true);
103
- setChannel(channel);
104
- },
105
- [client, customChannelId, customMessageId, initMessages, onSseMessage]
106
- );
107
-
108
- const closeChannel = useCallback(() => {
109
- setChannel((prevChannel: Channel | null) => {
110
- prevChannel?.close();
111
-
112
- return null;
113
- });
114
- setIsOpen(false);
115
- setIsResetting(false);
116
- setIsConnecting(false);
117
- setConversation(null);
118
- }, []);
119
-
120
- const sendMessage = useCallback(
121
- (payload: Pick<FetchSsePayload, 'text'> & Partial<Pick<FetchSsePayload, 'payload'>>) =>
122
- channel?.sendMessage({ ...payload, customMessageId }),
123
- [channel, customMessageId]
124
- );
125
-
126
- useEffect(() => {
127
- if (!channel && isOpen) resetChannel(resetPayload);
128
- }, [channel, isOpen, resetChannel, resetPayload]);
129
-
130
- useEffect(() => {
131
- return (): void => closeChannel();
132
- }, [closeChannel]);
133
-
134
- return useMemo(
135
- () => ({
136
- isOpen,
137
- isResetting,
138
- isConnecting,
139
- conversation,
140
- sendMessage,
141
- resetChannel,
142
- closeChannel,
143
- }),
144
- [
145
- isOpen,
146
- isResetting,
147
- isConnecting,
148
- conversation,
149
- sendMessage,
150
- resetChannel,
151
- closeChannel,
152
- ]
153
- );
154
- }
@@ -1,18 +0,0 @@
1
- import { useEffect, useState } from 'react';
2
-
3
- export function useDebounce<ValueType>(
4
- value: ValueType,
5
- delay?: number
6
- ): ValueType {
7
- const [debouncedValue, setDebouncedValue] = useState(value);
8
-
9
- useEffect(() => {
10
- const handler = window.setTimeout(() => {
11
- setDebouncedValue(value);
12
- }, delay ?? 300);
13
-
14
- return (): void => clearTimeout(handler);
15
- }, [value, delay]);
16
-
17
- return debouncedValue;
18
- }
@@ -1,19 +0,0 @@
1
- import { useRef } from 'react';
2
- import { isEqual } from '../utils/is';
3
-
4
- /**
5
- * useDeepCompareMemo: React hook that only recomputes the value when deps deeply change.
6
- * @param factory - function to create the value
7
- * @param deps - dependency array (deep compared)
8
- */
9
- export function useDeepCompareMemo<T>(factory: () => T, deps: unknown[]): T {
10
- const valueRef = useRef<T>();
11
- const depsRef = useRef<unknown[]>();
12
-
13
- if (!depsRef.current || !isEqual(depsRef.current, deps)) {
14
- depsRef.current = deps;
15
- valueRef.current = factory();
16
- }
17
-
18
- return valueRef.current as T;
19
- }