@asgard-js/react 0.0.43-canary.9 → 0.0.44-canary.1

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 (139) hide show
  1. package/README.md +45 -1
  2. package/dist/components/chatbot/api-key-input/api-key-input.d.ts.map +1 -1
  3. package/dist/components/chatbot/chatbot.d.ts +2 -3
  4. package/dist/components/chatbot/chatbot.d.ts.map +1 -1
  5. package/dist/context/asgard-service-context.d.ts +1 -1
  6. package/dist/context/asgard-service-context.d.ts.map +1 -1
  7. package/dist/context/asgard-theme-context.d.ts +2 -0
  8. package/dist/context/asgard-theme-context.d.ts.map +1 -1
  9. package/dist/hooks/use-channel.d.ts +1 -1
  10. package/dist/hooks/use-channel.d.ts.map +1 -1
  11. package/dist/hooks/use-on-screen-keyboard-scroll-fix.d.ts +1 -1
  12. package/dist/hooks/use-on-screen-keyboard-scroll-fix.d.ts.map +1 -1
  13. package/dist/{style.css → index.css} +1 -1
  14. package/dist/index.js +21396 -21771
  15. package/package.json +3 -3
  16. package/.babelrc +0 -12
  17. package/eslint.config.cjs +0 -12
  18. package/src/components/.DS_Store +0 -0
  19. package/src/components/chatbot/api-key-input/api-key-input.module.scss +0 -184
  20. package/src/components/chatbot/api-key-input/api-key-input.tsx +0 -129
  21. package/src/components/chatbot/api-key-input/index.ts +0 -1
  22. package/src/components/chatbot/chatbot-body/chatbot-body.module.scss +0 -13
  23. package/src/components/chatbot/chatbot-body/chatbot-body.tsx +0 -45
  24. package/src/components/chatbot/chatbot-body/conversation-message-renderer.tsx +0 -55
  25. package/src/components/chatbot/chatbot-body/index.ts +0 -1
  26. package/src/components/chatbot/chatbot-container/chatbot-container.module.scss +0 -41
  27. package/src/components/chatbot/chatbot-container/chatbot-container.tsx +0 -49
  28. package/src/components/chatbot/chatbot-container/chatbot-full-screen-container.tsx +0 -54
  29. package/src/components/chatbot/chatbot-footer/chatbot-footer.module.scss +0 -67
  30. package/src/components/chatbot/chatbot-footer/chatbot-footer.tsx +0 -140
  31. package/src/components/chatbot/chatbot-footer/index.ts +0 -1
  32. package/src/components/chatbot/chatbot-footer/speech-input-button.tsx +0 -132
  33. package/src/components/chatbot/chatbot-header/chatbot-header.module.scss +0 -48
  34. package/src/components/chatbot/chatbot-header/chatbot-header.tsx +0 -98
  35. package/src/components/chatbot/chatbot-header/index.ts +0 -1
  36. package/src/components/chatbot/chatbot.spec.tsx +0 -8
  37. package/src/components/chatbot/chatbot.tsx +0 -233
  38. package/src/components/chatbot/profile-icon.tsx +0 -26
  39. package/src/components/index.ts +0 -2
  40. package/src/components/templates/avatar/avatar.module.scss +0 -6
  41. package/src/components/templates/avatar/avatar.tsx +0 -28
  42. package/src/components/templates/avatar/index.ts +0 -1
  43. package/src/components/templates/button-template/button-template.module.scss +0 -0
  44. package/src/components/templates/button-template/button-template.tsx +0 -45
  45. package/src/components/templates/button-template/card.module.scss +0 -58
  46. package/src/components/templates/button-template/card.spec.tsx +0 -213
  47. package/src/components/templates/button-template/card.tsx +0 -123
  48. package/src/components/templates/button-template/index.ts +0 -1
  49. package/src/components/templates/carousel-template/carousel-template.module.scss +0 -15
  50. package/src/components/templates/carousel-template/carousel-template.tsx +0 -49
  51. package/src/components/templates/carousel-template/index.ts +0 -1
  52. package/src/components/templates/chart-template/chart-template.module.scss +0 -52
  53. package/src/components/templates/chart-template/chart-template.tsx +0 -75
  54. package/src/components/templates/chart-template/index.ts +0 -1
  55. package/src/components/templates/hint-template/hint-template.module.scss +0 -43
  56. package/src/components/templates/hint-template/hint-template.tsx +0 -76
  57. package/src/components/templates/hint-template/index.ts +0 -1
  58. package/src/components/templates/image-template/image-template.module.scss +0 -67
  59. package/src/components/templates/image-template/image-template.tsx +0 -58
  60. package/src/components/templates/image-template/index.ts +0 -1
  61. package/src/components/templates/index.ts +0 -10
  62. package/src/components/templates/quick-replies/index.ts +0 -1
  63. package/src/components/templates/quick-replies/quick-replies.module.scss +0 -16
  64. package/src/components/templates/quick-replies/quick-replies.tsx +0 -47
  65. package/src/components/templates/template-box/index.ts +0 -2
  66. package/src/components/templates/template-box/template-box-content.module.scss +0 -13
  67. package/src/components/templates/template-box/template-box-content.tsx +0 -30
  68. package/src/components/templates/template-box/template-box.module.scss +0 -19
  69. package/src/components/templates/template-box/template-box.tsx +0 -48
  70. package/src/components/templates/text-template/bot-typing-box.tsx +0 -81
  71. package/src/components/templates/text-template/bot-typing-placeholder.tsx +0 -28
  72. package/src/components/templates/text-template/index.ts +0 -3
  73. package/src/components/templates/text-template/text-template.module.scss +0 -131
  74. package/src/components/templates/text-template/text-template.tsx +0 -94
  75. package/src/components/templates/text-template/use-react-markdown-renderer.spec.tsx +0 -758
  76. package/src/components/templates/time/index.ts +0 -1
  77. package/src/components/templates/time/time.module.scss +0 -6
  78. package/src/components/templates/time/time.tsx +0 -34
  79. package/src/context/asgard-app-initialization-context.tsx +0 -154
  80. package/src/context/asgard-service-context.tsx +0 -148
  81. package/src/context/asgard-template-context.tsx +0 -83
  82. package/src/context/asgard-theme-context.tsx +0 -546
  83. package/src/context/index.ts +0 -4
  84. package/src/hooks/index.ts +0 -11
  85. package/src/hooks/use-asgard-service-client.ts +0 -68
  86. package/src/hooks/use-channel.ts +0 -160
  87. package/src/hooks/use-debounce.ts +0 -18
  88. package/src/hooks/use-deep-compare-memo.ts +0 -19
  89. package/src/hooks/use-is-on-screen-keyboard-open.ts +0 -43
  90. package/src/hooks/use-on-screen-keyboard-scroll-fix.ts +0 -15
  91. package/src/hooks/use-prevent-over-scrolling.ts +0 -77
  92. package/src/hooks/use-react-markdown-renderer.tsx +0 -278
  93. package/src/hooks/use-resize-observer.tsx +0 -27
  94. package/src/hooks/use-update-vh.ts +0 -30
  95. package/src/hooks/use-viewport-size.ts +0 -51
  96. package/src/icons/add_a_photo.svg +0 -3
  97. package/src/icons/bot.svg +0 -14
  98. package/src/icons/close.svg +0 -3
  99. package/src/icons/distance.svg +0 -3
  100. package/src/icons/mic.svg +0 -3
  101. package/src/icons/photo_library.svg +0 -3
  102. package/src/icons/profile.svg +0 -28
  103. package/src/icons/refresh.svg +0 -3
  104. package/src/icons/send.svg +0 -3
  105. package/src/icons/stop.svg +0 -22
  106. package/src/icons/volume_up.svg +0 -3
  107. package/src/index.ts +0 -4
  108. package/src/models/bot-provider.ts +0 -108
  109. package/src/styles/_index.scss +0 -1
  110. package/src/styles/_styles.scss +0 -11
  111. package/src/styles/colors/_colors.scss +0 -10
  112. package/src/styles/colors/_index.scss +0 -1
  113. package/src/styles/colors/_variables.scss +0 -72
  114. package/src/styles/palette/_index.scss +0 -1
  115. package/src/styles/palette/_palette.scss +0 -42
  116. package/src/styles/palette/_variables.scss +0 -40
  117. package/src/styles/radius/_index.scss +0 -1
  118. package/src/styles/radius/_radius.scss +0 -8
  119. package/src/styles/radius/_variables.scss +0 -12
  120. package/src/styles/spacing/_index.scss +0 -1
  121. package/src/styles/spacing/_spacing.scss +0 -8
  122. package/src/styles/spacing/_variables.scss +0 -13
  123. package/src/styles/utils/_index.scss +0 -1
  124. package/src/styles/utils/_map.scss +0 -22
  125. package/src/test-setup.ts +0 -1
  126. package/src/utils/color-utils.ts +0 -52
  127. package/src/utils/deep-merge.ts +0 -26
  128. package/src/utils/extractors.ts +0 -20
  129. package/src/utils/format-time.ts +0 -8
  130. package/src/utils/index.ts +0 -1
  131. package/src/utils/is.ts +0 -72
  132. package/src/utils/selectors.ts +0 -7
  133. package/src/utils/uri-validation.spec.ts +0 -208
  134. package/src/utils/uri-validation.ts +0 -103
  135. package/tsconfig.json +0 -16
  136. package/tsconfig.lib.json +0 -63
  137. package/tsconfig.spec.json +0 -36
  138. package/tsconfig.tsbuildinfo +0 -1
  139. package/vite.config.ts +0 -63
@@ -1,28 +0,0 @@
1
- import { memo, ReactNode } from 'react';
2
- import styles from './avatar.module.scss';
3
- import BotSvg from '../../../icons/bot.svg?react';
4
- import clsx from 'clsx';
5
-
6
- interface AvatarProps {
7
- avatar?: string;
8
- }
9
-
10
- export const Avatar = memo((props: AvatarProps): ReactNode => {
11
- const { avatar } = props;
12
-
13
- if (avatar) {
14
- return (
15
- <img
16
- src={avatar}
17
- alt="Bot Avatar"
18
- className={clsx('asgard-avatar', styles.bot_avatar)}
19
- />
20
- );
21
- }
22
-
23
- return (
24
- <div className={clsx('asgard-avatar', styles.bot_avatar)}>
25
- <BotSvg />
26
- </div>
27
- );
28
- });
@@ -1 +0,0 @@
1
- export * from './avatar';
@@ -1,45 +0,0 @@
1
- import { ButtonMessageTemplate, ConversationBotMessage } from '@asgard-js/core';
2
- import { ReactNode } from 'react';
3
- import { TemplateBox, TemplateBoxContent } from '../template-box';
4
- import { Avatar } from '../avatar';
5
- import { Card } from './card';
6
- import { useAsgardContext } from '../../../context/asgard-service-context';
7
- import { useAsgardThemeContext } from '../../../context/asgard-theme-context';
8
-
9
- interface ButtonTemplateProps {
10
- message: ConversationBotMessage;
11
- }
12
-
13
- export function ButtonTemplate(props: ButtonTemplateProps): ReactNode {
14
- const { message } = props;
15
-
16
- const { template: themeTemplate } = useAsgardThemeContext();
17
-
18
- const { avatar } = useAsgardContext();
19
-
20
- const template = message.message.template as ButtonMessageTemplate;
21
-
22
- return (
23
- <TemplateBox
24
- className="asgard-button-template"
25
- type="bot"
26
- direction="horizontal"
27
- style={themeTemplate?.ButtonMessageTemplate?.style}
28
- >
29
- <Avatar avatar={avatar} />
30
- <TemplateBoxContent
31
- time={message.time}
32
- quickReplies={template?.quickReplies}
33
- >
34
- <Card
35
- template={template}
36
- customStyle={{
37
- button: {
38
- style: themeTemplate?.ButtonMessageTemplate?.button?.style ?? {},
39
- },
40
- }}
41
- />
42
- </TemplateBoxContent>
43
- </TemplateBox>
44
- );
45
- }
@@ -1,58 +0,0 @@
1
- .card_root {
2
- width: 255px;
3
- height: 368px;
4
- max-height: 380px;
5
- border-radius: 8px;
6
- background: rgba(51, 51, 51, 1);
7
- overflow: hidden;
8
- display: grid;
9
- grid-template-rows: max-content auto;
10
- }
11
-
12
- .card_content {
13
- display: grid;
14
- grid-template-rows: 1.5em auto max-content;
15
- gap: var(--asg-spacing-2);
16
- padding: 12px;
17
- line-height: 1.5em;
18
- }
19
-
20
- .card_title {
21
- color: white;
22
- margin: 0;
23
- font-size: 15px;
24
- }
25
-
26
- .card_description {
27
- color: rgba(140, 140, 140, 1);
28
- font-size: 13px;
29
- font-weight: 400;
30
- max-height: 4.5em;
31
- overflow: hidden;
32
- text-overflow: ellipsis;
33
- display: -webkit-box;
34
- line-clamp: 3;
35
- -webkit-line-clamp: 3;
36
- -webkit-box-orient: vertical;
37
- text-underline-position: from-font;
38
- text-decoration-skip-ink: none;
39
- }
40
-
41
- .card_actions {
42
- display: flex;
43
- flex-direction: column;
44
- gap: 8px;
45
-
46
- > button {
47
- width: 100%;
48
- height: 32px;
49
- line-height: 32px;
50
- text-align: center;
51
- border: none;
52
- border-radius: 4px;
53
- background: rgba(71, 103, 235, 1);
54
- color: white;
55
- font-size: 15px;
56
- cursor: pointer;
57
- }
58
- }
@@ -1,213 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
- import { render, screen, fireEvent } from '@testing-library/react';
3
- import { Card } from './card';
4
- import { MessageTemplateType } from '@asgard-js/core';
5
- import { useAsgardContext } from '../../../context/asgard-service-context';
6
- import { useAsgardTemplateContext } from '../../../context/asgard-template-context';
7
- import * as uriValidation from '../../../utils/uri-validation';
8
-
9
- // Mock the contexts
10
- vi.mock('../../../context/asgard-service-context');
11
- vi.mock('../../../context/asgard-template-context');
12
-
13
- // Mock the URI validation utility
14
- vi.mock('../../../utils/uri-validation');
15
-
16
- const mockUseAsgardContext = vi.mocked(useAsgardContext);
17
- const mockUseAsgardTemplateContext = vi.mocked(useAsgardTemplateContext);
18
- const mockSafeWindowOpen = vi.mocked(uriValidation.safeWindowOpen);
19
-
20
- describe('Card Component - Security Tests', () => {
21
- const mockSendMessage = vi.fn();
22
- const mockOnTemplateBtnClick = vi.fn();
23
- const defaultLinkTarget = '_blank';
24
-
25
- // Define malicious URI as variable to avoid ESLint script URL warning
26
- // eslint-disable-next-line no-script-url
27
- const maliciousJsUri = 'javascript:alert("xss")';
28
-
29
- const baseTemplate = {
30
- type: MessageTemplateType.BUTTON,
31
- title: 'Test Card',
32
- text: 'Test description',
33
- thumbnailImageUrl: 'https://example.com/image.jpg',
34
- imageAspectRatio: 'rectangle' as const,
35
- imageSize: 'cover' as const,
36
- imageBackgroundColor: '#ffffff',
37
- defaultAction: {
38
- type: 'message' as const,
39
- text: 'Default action',
40
- },
41
- quickReplies: [],
42
- buttons: [
43
- {
44
- label: 'Safe Link',
45
- action: {
46
- type: 'uri' as const,
47
- uri: 'https://example.com',
48
- },
49
- },
50
- {
51
- label: 'Malicious Link',
52
- action: {
53
- type: 'uri' as const,
54
- uri: maliciousJsUri,
55
- },
56
- },
57
- ],
58
- };
59
-
60
- beforeEach(() => {
61
- mockUseAsgardContext.mockReturnValue({
62
- sendMessage: mockSendMessage,
63
- client: null,
64
- isOpen: false,
65
- isResetting: false,
66
- isConnecting: false,
67
- conversation: null,
68
- resetChannel: vi.fn(),
69
- closeChannel: vi.fn(),
70
- avatar: null,
71
- });
72
-
73
- mockUseAsgardTemplateContext.mockReturnValue({
74
- onTemplateBtnClick: mockOnTemplateBtnClick,
75
- defaultLinkTarget,
76
- onErrorClick: undefined,
77
- errorMessageRenderer: undefined,
78
- });
79
-
80
- mockSafeWindowOpen.mockReturnValue(null);
81
- });
82
-
83
- afterEach(() => {
84
- vi.clearAllMocks();
85
- });
86
-
87
- describe('URI security validation', () => {
88
- it('should call safeWindowOpen for URI actions instead of window.open directly', () => {
89
- render(<Card template={baseTemplate} />);
90
-
91
- const safeButton = screen.getByText('Safe Link');
92
- fireEvent.click(safeButton);
93
-
94
- expect(mockSafeWindowOpen).toHaveBeenCalledWith(
95
- 'https://example.com',
96
- '_blank'
97
- );
98
- });
99
-
100
- it('should call safeWindowOpen for malicious URIs (letting validation utility handle security)', () => {
101
- render(<Card template={baseTemplate} />);
102
-
103
- const maliciousButton = screen.getByText('Malicious Link');
104
- fireEvent.click(maliciousButton);
105
-
106
- expect(mockSafeWindowOpen).toHaveBeenCalledWith(
107
- maliciousJsUri,
108
- '_blank'
109
- );
110
- });
111
-
112
- it('should use action target if provided', () => {
113
- const templateWithTarget = {
114
- ...baseTemplate,
115
- buttons: [
116
- {
117
- label: 'Link with Target',
118
- action: {
119
- type: 'uri' as const,
120
- uri: 'https://example.com',
121
- target: '_self' as const,
122
- },
123
- },
124
- ],
125
- };
126
-
127
- render(<Card template={templateWithTarget} />);
128
-
129
- const button = screen.getByText('Link with Target');
130
- fireEvent.click(button);
131
-
132
- expect(mockSafeWindowOpen).toHaveBeenCalledWith(
133
- 'https://example.com',
134
- '_self'
135
- );
136
- });
137
-
138
- it('should fallback to defaultLinkTarget when no action target', () => {
139
- mockUseAsgardTemplateContext.mockReturnValue({
140
- onTemplateBtnClick: mockOnTemplateBtnClick,
141
- defaultLinkTarget: '_parent',
142
- });
143
-
144
- render(<Card template={baseTemplate} />);
145
-
146
- const safeButton = screen.getByText('Safe Link');
147
- fireEvent.click(safeButton);
148
-
149
- expect(mockSafeWindowOpen).toHaveBeenCalledWith(
150
- 'https://example.com',
151
- '_parent'
152
- );
153
- });
154
-
155
- it('should fallback to _blank when no action target or defaultLinkTarget', () => {
156
- mockUseAsgardTemplateContext.mockReturnValue({
157
- onTemplateBtnClick: mockOnTemplateBtnClick,
158
- defaultLinkTarget: undefined,
159
- });
160
-
161
- render(<Card template={baseTemplate} />);
162
-
163
- const safeButton = screen.getByText('Safe Link');
164
- fireEvent.click(safeButton);
165
-
166
- expect(mockSafeWindowOpen).toHaveBeenCalledWith(
167
- 'https://example.com',
168
- '_blank'
169
- );
170
- });
171
-
172
- it('should handle uppercase URI action type', () => {
173
- const templateWithUppercase = {
174
- ...baseTemplate,
175
- buttons: [
176
- {
177
- label: 'Uppercase URI',
178
- action: {
179
- type: 'URI' as const,
180
- uri: 'https://example.com',
181
- },
182
- },
183
- ],
184
- };
185
-
186
- render(<Card template={templateWithUppercase} />);
187
-
188
- const button = screen.getByText('Uppercase URI');
189
- fireEvent.click(button);
190
-
191
- expect(mockSafeWindowOpen).toHaveBeenCalledWith(
192
- 'https://example.com',
193
- '_blank'
194
- );
195
- });
196
- });
197
-
198
- describe('basic rendering', () => {
199
- it('should render card with title and description', () => {
200
- render(<Card template={baseTemplate} />);
201
-
202
- expect(screen.getByText('Test Card')).toBeDefined();
203
- expect(screen.getByText('Test description')).toBeDefined();
204
- });
205
-
206
- it('should render buttons', () => {
207
- render(<Card template={baseTemplate} />);
208
-
209
- expect(screen.getByText('Safe Link')).toBeDefined();
210
- expect(screen.getByText('Malicious Link')).toBeDefined();
211
- });
212
- });
213
- });
@@ -1,123 +0,0 @@
1
- import {
2
- MouseEventHandler,
3
- ReactNode,
4
- useCallback,
5
- useMemo,
6
- CSSProperties,
7
- } from 'react';
8
- import styles from './card.module.scss';
9
- import {
10
- ButtonAction,
11
- ButtonMessageTemplate,
12
- CarouselMessageTemplate,
13
- } from '@asgard-js/core';
14
- import { useAsgardContext } from '../../../context/asgard-service-context';
15
- import { useAsgardTemplateContext } from '../../../context/asgard-template-context';
16
- import { safeWindowOpen } from '../../../utils/uri-validation';
17
- import clsx from 'clsx';
18
-
19
- interface CardProps {
20
- template: ButtonMessageTemplate | CarouselMessageTemplate['columns'][number];
21
- customStyle?: {
22
- style?: CSSProperties;
23
- button?: {
24
- style?: CSSProperties;
25
- };
26
- };
27
- }
28
-
29
- export function Card(props: CardProps): ReactNode {
30
- const { template, customStyle } = props;
31
-
32
- const { sendMessage } = useAsgardContext();
33
- const { onTemplateBtnClick, defaultLinkTarget } = useAsgardTemplateContext();
34
-
35
- const src = useMemo(() => {
36
- return (
37
- template?.thumbnailImageUrl
38
- ?.replace(/^http:/, '')
39
- .replace(/^https:/, '') ||
40
- 'https://via.assets.so/img.jpg?w=200&h=270&tc=white&bg=#eeeeee'
41
- );
42
- }, [template]);
43
-
44
- const aspectRatio = useMemo(() => {
45
- switch (template?.imageAspectRatio) {
46
- case 'square':
47
- return '1 / 1';
48
- case 'rectangle':
49
- default:
50
- return '1.51 / 1';
51
- }
52
- }, [template]);
53
-
54
- const handleClick = useCallback(
55
- (action: ButtonAction): MouseEventHandler<HTMLButtonElement> => {
56
- return function clickHandler() {
57
- switch (action.type) {
58
- case 'message':
59
- case 'MESSAGE':
60
- sendMessage?.({ text: action.text });
61
-
62
- return;
63
- case 'uri':
64
- case 'URI':
65
- safeWindowOpen(
66
- action.uri,
67
- action.target || defaultLinkTarget || '_blank'
68
- );
69
-
70
- return;
71
- case 'emit':
72
- case 'EMIT':
73
- onTemplateBtnClick?.(action.payload, {
74
- sse: {
75
- sendMessage: (payload) => {
76
- sendMessage?.(payload);
77
- },
78
- },
79
- });
80
-
81
- return;
82
- }
83
- };
84
- },
85
- [sendMessage, onTemplateBtnClick, defaultLinkTarget]
86
- );
87
-
88
- return (
89
- <div
90
- className={clsx('asgard-card', styles.card_root)}
91
- style={customStyle?.style}
92
- >
93
- {template?.thumbnailImageUrl && (
94
- <img
95
- alt={template?.title}
96
- src={src}
97
- style={{
98
- display: 'block',
99
- width: '100%',
100
- maxHeight: '170px',
101
- objectFit: template?.imageSize,
102
- aspectRatio,
103
- }}
104
- />
105
- )}
106
- <div className={styles.card_content}>
107
- <h5 className={styles.card_title}>{template?.title}</h5>
108
- <div className={styles.card_description}>{template?.text}</div>
109
- <div className={styles.card_actions}>
110
- {template?.buttons?.map((btn: { label: string; action: ButtonAction }, index: number) => (
111
- <button
112
- key={index}
113
- onClick={handleClick(btn.action)}
114
- style={customStyle?.button?.style}
115
- >
116
- {btn.label}
117
- </button>
118
- ))}
119
- </div>
120
- </div>
121
- </div>
122
- );
123
- }
@@ -1 +0,0 @@
1
- export * from './button-template';
@@ -1,15 +0,0 @@
1
- .carousel_root {
2
- width: 100%;
3
- display: flex;
4
- flex-wrap: nowrap;
5
- overflow-x: scroll;
6
- gap: 8px;
7
-
8
- > div {
9
- flex: 0 0 auto;
10
- }
11
- }
12
-
13
- .carousel_time {
14
- justify-content: flex-end;
15
- }
@@ -1,49 +0,0 @@
1
- import { ReactNode } from 'react';
2
- import { TemplateBox, TemplateBoxContent } from '../template-box';
3
- import { Avatar } from '../avatar';
4
- import styles from './carousel-template.module.scss';
5
- import { Card } from '../button-template/card';
6
- import {
7
- CarouselMessageTemplate,
8
- ConversationBotMessage,
9
- ButtonMessageTemplate,
10
- } from '@asgard-js/core';
11
- import { Time } from '../time';
12
- import { useAsgardContext } from '../../../context/asgard-service-context';
13
- import { useAsgardThemeContext } from '../../../context/asgard-theme-context';
14
-
15
- interface CarouselTemplateProps {
16
- message: ConversationBotMessage;
17
- }
18
-
19
- export function CarouselTemplate(props: CarouselTemplateProps): ReactNode {
20
- const { message } = props;
21
-
22
- const { template: themeTemplate } = useAsgardThemeContext();
23
- const { avatar } = useAsgardContext();
24
-
25
- const template = message.message.template as CarouselMessageTemplate;
26
-
27
- return (
28
- <TemplateBox
29
- className="asgard-carousel-template"
30
- type="bot"
31
- direction="vertical"
32
- style={themeTemplate?.CarouselMessageTemplate?.style}
33
- >
34
- <Avatar avatar={avatar} />
35
- <TemplateBoxContent quickReplies={template.quickReplies}>
36
- <div className={styles.carousel_root}>
37
- {template.columns?.map((column: Omit<ButtonMessageTemplate, 'type' | 'quickReplies'>, index: number) => (
38
- <Card
39
- key={index}
40
- template={column}
41
- customStyle={themeTemplate?.CarouselMessageTemplate?.card}
42
- />
43
- ))}
44
- </div>
45
- </TemplateBoxContent>
46
- <Time className={styles.carousel_time} time={message.time} />
47
- </TemplateBox>
48
- );
49
- }
@@ -1 +0,0 @@
1
- export * from './carousel-template';
@@ -1,52 +0,0 @@
1
- .text {
2
- display: inline-block;
3
- padding: 8px 12px;
4
- border-radius: 8px;
5
- color: white;
6
- word-break: break-all;
7
-
8
- > span {
9
- word-break: break-all;
10
- }
11
-
12
- .md_container {
13
- display: inline-block;
14
-
15
- p {
16
- margin: 0;
17
- }
18
- }
19
- }
20
-
21
- .text--user {
22
- max-width: 75%;
23
- background: #4767eb;
24
- border-top-right-radius: 0;
25
- }
26
-
27
- .text--bot {
28
- max-width: 70%;
29
- background: #585858;
30
- border-top-left-radius: 0;
31
- }
32
-
33
- .chart_time {
34
- justify-content: flex-end;
35
- }
36
-
37
- .quick_replies_box {
38
- display: flex;
39
- flex-wrap: wrap;
40
- gap: 8px;
41
- }
42
-
43
- .quick_reply {
44
- font: inherit;
45
- font-size: 13px;
46
- padding: 4px 8px;
47
- border-radius: 8px;
48
- border: 1px solid #434343;
49
- background: rgba(88, 88, 88, 0.2);
50
- color: white;
51
- cursor: pointer;
52
- }
@@ -1,75 +0,0 @@
1
- import { ReactNode, useMemo, useState, CSSProperties } from 'react';
2
- import { TemplateBox, TemplateBoxContent } from '../template-box';
3
- import { Avatar } from '../avatar';
4
- import { ConversationBotMessage, ChartMessageTemplate } from '@asgard-js/core';
5
- import { Time } from '../time';
6
- import { useAsgardContext } from '../../../context/asgard-service-context';
7
- import { VegaLite, VisualizationSpec } from 'react-vega';
8
- import clsx from 'clsx';
9
- import classes from './chart-template.module.scss';
10
- import { useAsgardThemeContext } from '../../../context/asgard-theme-context';
11
-
12
- interface ChartTemplateProps {
13
- message: ConversationBotMessage;
14
- }
15
-
16
- export function ChartTemplate(props: ChartTemplateProps): ReactNode {
17
- const { message } = props;
18
- const template = message.message.template as ChartMessageTemplate;
19
-
20
- const { template: themeTemplate, botMessage } = useAsgardThemeContext();
21
- const { avatar } = useAsgardContext();
22
-
23
- const [option, setOption] = useState(
24
- template?.defaultChart ?? template?.chartOptions?.[0]?.type
25
- );
26
-
27
- const options = useMemo(() => template.chartOptions, [template]);
28
-
29
- const spec = useMemo(
30
- () =>
31
- (template?.chartOptions?.find((item: { type: string; title: string; spec: Record<string, unknown> }) => item.type === option)?.spec ??
32
- options[0].spec) as VisualizationSpec,
33
- [option, template.chartOptions, options]
34
- );
35
-
36
- const styles = useMemo<CSSProperties>(
37
- () => ({
38
- color: botMessage?.color,
39
- backgroundColor: botMessage?.backgroundColor,
40
- }),
41
- [botMessage]
42
- );
43
-
44
- return (
45
- <TemplateBox
46
- className="asgard-chart-template"
47
- type="bot"
48
- direction="vertical"
49
- style={themeTemplate?.ChartMessageTemplate?.style}
50
- >
51
- <Avatar avatar={avatar} />
52
- <div className={clsx(classes.text, classes['text--bot'])} style={styles}>
53
- <div>{template.title}</div>
54
- <div>{template.text}</div>
55
- </div>
56
- {options.length > 1 && (
57
- <div className={classes.quick_replies_box}>
58
- {options.map((option: { type: string; title: string; spec: Record<string, unknown> }) => (
59
- <button
60
- key={option.type}
61
- className={classes.quick_reply}
62
- onClick={() => setOption(option.type)}
63
- >
64
- {option.title}
65
- </button>
66
- ))}
67
- </div>
68
- )}
69
- <TemplateBoxContent quickReplies={template?.quickReplies}>
70
- <VegaLite spec={spec} />
71
- </TemplateBoxContent>
72
- <Time className={classes.chart_time} time={message.time} />
73
- </TemplateBox>
74
- );
75
- }
@@ -1 +0,0 @@
1
- export * from './chart-template';