@homecode/ui 5.8.0 → 5.9.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 (30) hide show
  1. package/dist/esm/index.js +6 -0
  2. package/dist/esm/src/components/Autocomplete/Autocomplete.js +13 -6
  3. package/dist/esm/src/components/Card/Card.styl.js +1 -1
  4. package/dist/esm/src/components/Chat/ChatFormattedText.js +323 -0
  5. package/dist/esm/src/components/Chat/ChatFormattedText.styl.js +7 -0
  6. package/dist/esm/src/components/Chat/ChatMessage.js +50 -0
  7. package/dist/esm/src/components/Chat/ChatMessage.styl.js +7 -0
  8. package/dist/esm/src/components/Chat/ChatPrompt.js +50 -0
  9. package/dist/esm/src/components/Chat/ChatPrompt.styl.js +7 -0
  10. package/dist/esm/src/components/Chat/ChatView.js +30 -0
  11. package/dist/esm/src/components/Chat/ChatView.styl.js +7 -0
  12. package/dist/esm/src/components/Chat/content.js +96 -0
  13. package/dist/esm/src/components/Dialogue/Dialogue.js +4 -2
  14. package/dist/esm/src/components/InputFile/InputFile.js +11 -4
  15. package/dist/esm/src/components/ThinkingOutline/ThinkingOutline.js +9 -0
  16. package/dist/esm/src/components/ThinkingOutline/ThinkingOutline.styl.js +7 -0
  17. package/dist/esm/types/src/components/Chat/Chat.types.d.ts +78 -0
  18. package/dist/esm/types/src/components/Chat/ChatFormattedText.d.ts +3 -0
  19. package/dist/esm/types/src/components/Chat/ChatMessage.d.ts +2 -0
  20. package/dist/esm/types/src/components/Chat/ChatPrompt.d.ts +2 -0
  21. package/dist/esm/types/src/components/Chat/ChatView.d.ts +2 -0
  22. package/dist/esm/types/src/components/Chat/content.d.ts +8 -0
  23. package/dist/esm/types/src/components/Chat/index.d.ts +6 -0
  24. package/dist/esm/types/src/components/Chat/types.d.ts +1 -0
  25. package/dist/esm/types/src/components/NestedMenu/NestedMenu.d.ts +1 -1
  26. package/dist/esm/types/src/components/NestedMenu/NestedMenu.types.d.ts +1 -0
  27. package/dist/esm/types/src/components/ThinkingOutline/ThinkingOutline.d.ts +5 -0
  28. package/dist/esm/types/src/components/ThinkingOutline/index.d.ts +2 -0
  29. package/dist/esm/types/src/components/index.d.ts +3 -0
  30. package/package.json +1 -1
package/dist/esm/index.js CHANGED
@@ -6,6 +6,11 @@ export { Calendar } from './src/components/Calendar/Calendar.js';
6
6
  export { Checkbox } from './src/components/Checkbox/Checkbox.js';
7
7
  export { Chip } from './src/components/Chip/Chip.js';
8
8
  export { Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, LinkCard } from './src/components/Card/Card.js';
9
+ export { ChatFormattedText } from './src/components/Chat/ChatFormattedText.js';
10
+ export { ChatMessage } from './src/components/Chat/ChatMessage.js';
11
+ export { ChatPrompt } from './src/components/Chat/ChatPrompt.js';
12
+ export { ChatView } from './src/components/Chat/ChatView.js';
13
+ export { getDisplayContent, getDisplayParts, isPlanMessageContent, parseSystemEvent } from './src/components/Chat/content.js';
9
14
  export { Container } from './src/components/Container/Container.js';
10
15
  export { DatePicker } from './src/components/DatePicker/DatePicker.js';
11
16
  export { DatePickerInput } from './src/components/DatePickerInput/DatePickerInput.js';
@@ -52,6 +57,7 @@ export { Spinner } from './src/components/Spinner/Spinner.js';
52
57
  export { Table } from './src/components/Table/Table.js';
53
58
  export { Tabs } from './src/components/Tabs/Tabs.js';
54
59
  export { TextShimmer } from './src/components/TextShimmer/TextShimmer.js';
60
+ export { ThinkingOutline } from './src/components/ThinkingOutline/ThinkingOutline.js';
55
61
  export { TextWithDeferTooltip } from './src/components/TextWithDeferTooltip/TextWithDeferTooltip.js';
56
62
  export { Tooltip } from './src/components/Tooltip/Tooltip.js';
57
63
  export { H1, H2, H3, H4, H5, H6 } from './src/components/Text/Text.js';
@@ -27,6 +27,19 @@ import '../Checkbox/Checkbox.styl.js';
27
27
  import '../Chip/Chip.styl.js';
28
28
  import '../Tooltip/Tooltip.js';
29
29
  import '../Card/Card.js';
30
+ import '../Router/context.js';
31
+ import '../Router/Link/Link.styl.js';
32
+ import '../Portal/Portal.js';
33
+ import '../Paranja/Paranja.styl.js';
34
+ import '../Table/Table.styl.js';
35
+ import '../Chat/ChatFormattedText.styl.js';
36
+ import '../Expand/Expand.styl.js';
37
+ import '../Chat/ChatMessage.styl.js';
38
+ import '../PromptComposer/PromptComposer.js';
39
+ import '../ThinkingOutline/ThinkingOutline.styl.js';
40
+ import '../Chat/ChatPrompt.styl.js';
41
+ import '../TextShimmer/TextShimmer.js';
42
+ import '../Chat/ChatView.styl.js';
30
43
  import '../Container/Container.js';
31
44
  import '../DatePicker/DatePicker.styl.js';
32
45
  import 'moment';
@@ -35,7 +48,6 @@ import '../Dialogue/Dialogue.js';
35
48
  import '../../tools/queryParams.js';
36
49
  import '../Draggable/Draggable.styl.js';
37
50
  import '../DropZone/DropZone.styl.js';
38
- import '../Expand/Expand.styl.js';
39
51
  import '../Flex/Flex.styl.js';
40
52
  import '../Form/Form.styl.js';
41
53
  import '../Form/Validator.js';
@@ -56,15 +68,12 @@ import '@tiptap/react';
56
68
  import { Menu } from '../Menu/Menu.js';
57
69
  import '../../tiptap/slash-mention/SlashSuggestionList.styl.js';
58
70
  import '../../services/i18n.js';
59
- import '../Portal/Portal.js';
60
- import '../Paranja/Paranja.styl.js';
61
71
  import '../LightBox/LightBox.styl.js';
62
72
  import '../NestedMenu/NestedMenu.js';
63
73
  import '../Notifications/store.js';
64
74
  import '../Notifications/Notifications.styl.js';
65
75
  import '../PopupMenu/PopupMenu.styl.js';
66
76
  import '../Progress/Progress.styl.js';
67
- import '../PromptComposer/PromptComposer.js';
68
77
  import '@tiptap/extensions';
69
78
  import '@tiptap/starter-kit';
70
79
  import '../PromptComposer/PromptComposer.styl.js';
@@ -72,9 +81,7 @@ import '../RadioGroup/RadioGroupContext.js';
72
81
  import '../RadioButton/RadioButton.styl.js';
73
82
  import '../RadioGroup/RadioGroup.styl.js';
74
83
  import '../Router/Router.js';
75
- import '../Table/Table.styl.js';
76
84
  import '../Tabs/Tabs.styl.js';
77
- import '../TextShimmer/TextShimmer.js';
78
85
  import '../TextWithDeferTooltip/TextWithDeferTooltip.styl.js';
79
86
  import '../Text/Text.js';
80
87
  import '../Theme/Theme.defaults.js';
@@ -1,6 +1,6 @@
1
1
  import styleInject from '../../../node_modules/style-inject/dist/style-inject.es.js';
2
2
 
3
- var css_248z = ".Card_root__khJ4u{background-color:var(--surface-color);border-radius:var(--border-radius-l);display:flex;flex-direction:column;gap:var(--p-5);max-height:100%;position:relative}.Card_root__khJ4u.Card_blur__VbZXN{-webkit-backdrop-filter:blur(20px);backdrop-filter:blur(20px);background-color:var(--decent-color-alpha-500)}.Card_root__khJ4u.Card_padding-xs__dd13Q{border-radius:var(--p-3);padding:var(--p-2)}.Card_root__khJ4u.Card_padding-s__S7iiZ{border-radius:var(--p-4);padding:var(--p-3)}.Card_root__khJ4u.Card_padding-m__thC3O{border-radius:var(--p-6);padding:var(--p-5)}.Card_root__khJ4u.Card_padding-l__gtTEF{border-radius:var(--p-8);padding:var(--p-8)}.Card_root__khJ4u.Card_padding-xl__y01o1{border-radius:var(--p-11);padding:var(--p-10)}.Card_header__LDTGV{align-items:flex-start;display:flex;gap:var(--p-5);justify-content:space-between}.Card_header__LDTGV:has([data-slot=card-action]){grid-template-columns:1fr auto}.Card_icon__aRlE5{align-items:center;border-radius:var(--p-2);box-shadow:inset 0 0 0 1px var(--decent-color-alpha-200);display:flex;flex-shrink:0;height:48px;justify-content:center;width:48px}.Card_icon__aRlE5.Card_withBackground__lIrjx{background-color:var(--accent-color-alpha-100);box-shadow:none}.Card_icon__aRlE5>img,.Card_icon__aRlE5>svg{height:20px;width:20px}.Card_headerText__hawuL{flex-grow:1;overflow:hidden}.Card_scroll__uDcXL{max-height:100%;overflow:hidden;padding-right:var(--p-5);width:calc(100% + var(--p-5))}.Card_scroll__uDcXL [data-slot=card-content]{padding-right:1px}.Card_centered__0YX4F,.Card_fullHeight__i3n8e{display:flex;flex-direction:column}.Card_centered__0YX4F{align-items:center;justify-content:center}.Card_fullHeight__i3n8e{flex-grow:1}.Card_description__RTQTR,.Card_title__Z1SQz{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.Card_title__Z1SQz{font-size:120%;font-weight:500;line-height:1.2}.Card_description__RTQTR{color:var(--accent-color-alpha-500);max-width:100%;word-break:break-word}.Card_action__viIuL{grid-row-span:2;align-self:start;grid-column-start:2;grid-row-start:1;justify-self:end}.Card_footer__T0DXA{align-items:center;display:flex;flex-shrink:0;justify-content:space-between;overflow:hidden}";
3
+ var css_248z = ".Card_root__khJ4u{background-color:var(--surface-color);border-radius:var(--border-radius-l);display:flex;flex-direction:column;gap:var(--p-5);max-height:100%;position:relative}.Card_root__khJ4u.Card_blur__VbZXN{-webkit-backdrop-filter:blur(20px);backdrop-filter:blur(20px);background-color:var(--decent-color-alpha-500)}.Card_root__khJ4u.Card_padding-xs__dd13Q{border-radius:var(--p-3);padding:var(--p-2)}.Card_root__khJ4u.Card_padding-s__S7iiZ{border-radius:var(--p-4);padding:var(--p-3)}.Card_root__khJ4u.Card_padding-m__thC3O{border-radius:var(--p-6);padding:var(--p-5)}.Card_root__khJ4u.Card_padding-l__gtTEF{border-radius:var(--p-8);padding:var(--p-8)}.Card_root__khJ4u.Card_padding-xl__y01o1{border-radius:var(--p-11);padding:var(--p-10)}.Card_header__LDTGV{align-items:flex-start;display:flex;gap:var(--p-5);justify-content:space-between}.Card_header__LDTGV:has([data-slot=card-action]){grid-template-columns:1fr auto}.Card_icon__aRlE5{align-items:center;border-radius:var(--p-2);box-shadow:inset 0 0 0 1px var(--decent-color-alpha-200);display:flex;flex-shrink:0;height:48px;justify-content:center;width:48px}.Card_icon__aRlE5.Card_withBackground__lIrjx{background-color:var(--accent-color-alpha-100);box-shadow:none}.Card_icon__aRlE5>img,.Card_icon__aRlE5>svg{height:20px;width:20px}.Card_headerText__hawuL{flex-grow:1;overflow:hidden}.Card_scroll__uDcXL{max-height:100%;overflow:hidden;padding-right:var(--p-5);width:calc(100% + var(--p-5))}.Card_scroll__uDcXL [data-slot=card-content]{padding-right:1px}.Card_centered__0YX4F,.Card_fullHeight__i3n8e{display:flex;flex-direction:column}.Card_centered__0YX4F{align-items:center;justify-content:center}.Card_fullHeight__i3n8e{flex-grow:1}.Card_description__RTQTR,.Card_title__Z1SQz{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.Card_title__Z1SQz{font-size:120%;font-weight:500;line-height:1.2}.Card_description__RTQTR{color:var(--accent-color-alpha-500);max-width:100%;word-break:break-word}.Card_action__viIuL{grid-row-span:2;align-self:start;grid-column-start:2;grid-row-start:1;justify-self:end}.Card_footer__T0DXA{align-items:center;display:flex;flex-shrink:0;justify-content:space-between;overflow:visible}";
4
4
  var S = {"root":"Card_root__khJ4u","blur":"Card_blur__VbZXN","padding-xs":"Card_padding-xs__dd13Q","padding-s":"Card_padding-s__S7iiZ","padding-m":"Card_padding-m__thC3O","padding-l":"Card_padding-l__gtTEF","padding-xl":"Card_padding-xl__y01o1","header":"Card_header__LDTGV","icon":"Card_icon__aRlE5","withBackground":"Card_withBackground__lIrjx","headerText":"Card_headerText__hawuL","scroll":"Card_scroll__uDcXL","centered":"Card_centered__0YX4F","fullHeight":"Card_fullHeight__i3n8e","title":"Card_title__Z1SQz","description":"Card_description__RTQTR","action":"Card_action__viIuL","footer":"Card_footer__T0DXA"};
5
5
  styleInject(css_248z);
6
6
 
@@ -0,0 +1,323 @@
1
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
+ import React__default from 'react';
3
+ import { Button } from '../Button/Button.js';
4
+ import { Link } from '../Router/Link/Link.js';
5
+ import { Table } from '../Table/Table.js';
6
+ import { Tooltip } from '../Tooltip/Tooltip.js';
7
+ import S from './ChatFormattedText.styl.js';
8
+
9
+ function findJsonEndExclusive(content, start) {
10
+ const first = content[start];
11
+ if (first !== '{' && first !== '[')
12
+ return -1;
13
+ const stack = first === '{' ? ['}'] : [']'];
14
+ let i = start + 1;
15
+ let inString = false;
16
+ let escape = false;
17
+ while (i < content.length && stack.length > 0) {
18
+ const c = content[i];
19
+ if (inString) {
20
+ if (escape)
21
+ escape = false;
22
+ else if (c === '\\')
23
+ escape = true;
24
+ else if (c === '"')
25
+ inString = false;
26
+ i++;
27
+ continue;
28
+ }
29
+ if (c === '"') {
30
+ inString = true;
31
+ i++;
32
+ continue;
33
+ }
34
+ if (c === '{') {
35
+ stack.push('}');
36
+ i++;
37
+ continue;
38
+ }
39
+ if (c === '[') {
40
+ stack.push(']');
41
+ i++;
42
+ continue;
43
+ }
44
+ if (c === '}' || c === ']') {
45
+ if (c !== stack[stack.length - 1])
46
+ return -1;
47
+ stack.pop();
48
+ i++;
49
+ continue;
50
+ }
51
+ i++;
52
+ }
53
+ return stack.length > 0 ? -1 : i;
54
+ }
55
+ function applyInjectors(text, injectors) {
56
+ let result = [text];
57
+ injectors.forEach(fn => {
58
+ let i = 0;
59
+ while (i < result.length) {
60
+ const item = result[i];
61
+ if (typeof item === 'string') {
62
+ const res = fn(item);
63
+ if (!res) {
64
+ i++;
65
+ continue;
66
+ }
67
+ const { elem, index, length } = res;
68
+ if (index >= 0) {
69
+ const before = item.substring(0, index);
70
+ const after = item.substring(index + length);
71
+ result.splice(i, 1, before, elem, after);
72
+ if (after.length > 0)
73
+ continue;
74
+ }
75
+ }
76
+ i++;
77
+ }
78
+ });
79
+ return result;
80
+ }
81
+ function ChatFormattedText({ text, className, onButtonClick, }) {
82
+ const injectLines = (content) => {
83
+ const matches = content.match(/\n---\n/);
84
+ if (!matches)
85
+ return null;
86
+ return {
87
+ elem: jsx("div", { className: S.line }),
88
+ index: matches.index,
89
+ length: matches[0].length,
90
+ };
91
+ };
92
+ const injectBullet = (content) => {
93
+ const matches = content.match(/(\n|^)([ \t]*)(-|\*|\+)\s/);
94
+ if (!matches)
95
+ return null;
96
+ return {
97
+ elem: (jsxs(Fragment, { children: [matches[1] === '\n' && jsx("br", {}), jsx("div", { className: S.bullet })] })),
98
+ index: matches.index,
99
+ length: matches[0].length,
100
+ };
101
+ };
102
+ const injectNumbered = (content) => {
103
+ const matches = content.match(/(\n|^)([ \t]*)(\d+)\.\s+/);
104
+ if (!matches)
105
+ return null;
106
+ return {
107
+ elem: (jsxs(Fragment, { children: [matches[1] === '\n' && jsx("br", {}), jsxs("span", { className: S.numberedIndex, children: [matches[3], "."] })] })),
108
+ index: matches.index,
109
+ length: matches[0].length,
110
+ };
111
+ };
112
+ const injectBold = (content) => {
113
+ const matches = content.match(/\*\*(.*?)\*\*/);
114
+ if (!matches)
115
+ return null;
116
+ return {
117
+ elem: jsx("strong", { children: matches[1] }),
118
+ index: matches.index,
119
+ length: matches[0].length,
120
+ };
121
+ };
122
+ const injectItalic = (content) => {
123
+ const matches = content.match(/\*(.*?)\*/);
124
+ if (!matches)
125
+ return null;
126
+ return {
127
+ elem: jsx("em", { children: matches[1] }),
128
+ index: matches.index,
129
+ length: matches[0].length,
130
+ };
131
+ };
132
+ const injectCodeBlock = (content) => {
133
+ const multiline = content.match(/```(\w+)?[\s\n]*([\s\S]*?)```/);
134
+ if (multiline) {
135
+ return {
136
+ elem: jsx("code", { className: S.codeBlock, children: multiline[2].trim() }),
137
+ index: multiline.index,
138
+ length: multiline[0].length,
139
+ };
140
+ }
141
+ const inline = content.match(/`([^`\n]+)`/);
142
+ if (!inline)
143
+ return null;
144
+ return {
145
+ elem: jsx("code", { className: S.codeInline, children: inline[1] }),
146
+ index: inline.index,
147
+ length: inline[0].length,
148
+ };
149
+ };
150
+ const injectPrettyJson = (content) => {
151
+ let searchFrom = 0;
152
+ while (searchFrom < content.length) {
153
+ let start = -1;
154
+ for (let j = searchFrom; j < content.length; j++) {
155
+ if (content[j] === '{' || content[j] === '[') {
156
+ start = j;
157
+ break;
158
+ }
159
+ }
160
+ if (start < 0)
161
+ return null;
162
+ const endExclusive = findJsonEndExclusive(content, start);
163
+ if (endExclusive < 0) {
164
+ searchFrom = start + 1;
165
+ continue;
166
+ }
167
+ const slice = content.slice(start, endExclusive);
168
+ try {
169
+ const parsed = JSON.parse(slice);
170
+ return {
171
+ elem: (jsx("pre", { className: S.jsonPre, children: JSON.stringify(parsed, null, 2) })),
172
+ index: start,
173
+ length: slice.length,
174
+ };
175
+ }
176
+ catch {
177
+ searchFrom = start + 1;
178
+ }
179
+ }
180
+ return null;
181
+ };
182
+ const injectLinks = (content) => {
183
+ const markdown = content.match(/\[([^\]]+)\]\(([^)]+)\)/);
184
+ if (markdown) {
185
+ let url = markdown[2];
186
+ if (url.startsWith('www.'))
187
+ url = `https://${url}`;
188
+ return {
189
+ elem: (jsx(Tooltip, { content: url, direction: "top", children: jsx(Link, { href: url, inline: true, target: "_blank", children: markdown[1] }) })),
190
+ index: markdown.index,
191
+ length: markdown[0].length,
192
+ };
193
+ }
194
+ const bareDomainTlds = 'com|org|net|edu|gov|mil|int|info|biz|co|io|ai|app|dev|me|tv|cc|ly|sh|so|gg|fm|ws|xyz|tech|cloud|store|online|site|shop|blog|news|link|page|uk|us|ca|de|fr|jp|cn|ru|br|in|au|it|es|nl|se|no|fi|pl|ch|be|at|dk|cz|gr|hu|ie|pt|ro|tr|kr|mx|za|sg|hk|tw|nz|il|ae|ua';
195
+ const matches = content.match(new RegExp(`(https?:\\/\\/[^\\s<>"']+|www\\.[^\\s<>"']+|[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*\\.(?:${bareDomainTlds})\\b[^\\s<>"']*)`, 'i'));
196
+ if (!matches)
197
+ return null;
198
+ let url = matches[0];
199
+ if (url.startsWith('www.'))
200
+ url = `https://${url}`;
201
+ return {
202
+ elem: (jsx(Tooltip, { content: url, direction: "top", children: jsx(Link, { href: url, inline: true, target: "_blank", children: matches[0] }) })),
203
+ index: matches.index,
204
+ length: matches[0].length,
205
+ };
206
+ };
207
+ const injectButtons = (content) => {
208
+ if (!onButtonClick)
209
+ return null;
210
+ const matches = content.match(/\[(.*?):(.*?)\|([^\]]+)\]/);
211
+ if (!matches)
212
+ return null;
213
+ const [data, label] = matches[0]
214
+ .replace('[', '')
215
+ .replace(']', '')
216
+ .split('|');
217
+ const [varName, value] = data.split(':');
218
+ return {
219
+ elem: (jsx(Button, { variant: "default", size: "s", round: true, onClick: () => onButtonClick({ text: label, [varName]: value }), children: label })),
220
+ index: matches.index,
221
+ length: matches[0].length,
222
+ };
223
+ };
224
+ const headingTags = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
225
+ const processCellContent = (value, depth = 0) => applyInjectors(value, [
226
+ injectCodeBlock,
227
+ injectPrettyJson,
228
+ ...(depth === 0
229
+ ? [
230
+ (content) => {
231
+ const matches = content.match(/(^|\n)(#{1,6})\s+([^\n]+)/);
232
+ if (!matches)
233
+ return null;
234
+ const Tag = headingTags[Math.min(matches[2].length, 6) - 1];
235
+ return {
236
+ elem: React__default.createElement(Tag, {}, ...processCellContent(matches[3], depth + 1)),
237
+ index: matches.index,
238
+ length: matches[0].length,
239
+ };
240
+ },
241
+ ]
242
+ : []),
243
+ injectLines,
244
+ injectLinks,
245
+ injectBold,
246
+ injectItalic,
247
+ injectBullet,
248
+ injectNumbered,
249
+ injectButtons,
250
+ ]);
251
+ const injectHeading = (content) => {
252
+ const matches = content.match(/(^|\n)(#{1,6})\s+([^\n]+)/);
253
+ if (!matches)
254
+ return null;
255
+ const Tag = headingTags[Math.min(matches[2].length, 6) - 1];
256
+ return {
257
+ elem: React__default.createElement(Tag, {}, ...processCellContent(matches[3], 1)),
258
+ index: matches.index,
259
+ length: matches[0].length,
260
+ };
261
+ };
262
+ const injectTables = (content) => {
263
+ const withSep = content.match(/(\n|^)(\|[^\n]+\|\s*\n)(\|[\s:-]+(?:\|[\s:-]+)*\|\s*\n)((?:\|[^\n]+\|\s*\n?)+)/);
264
+ const withoutSep = withSep
265
+ ? null
266
+ : content.match(/(\n|^)(\|[^\n]+\|\s*\n)((?:\|[^\n]+\|\s*\n?)+)/);
267
+ const matches = withSep || withoutSep;
268
+ if (!matches)
269
+ return null;
270
+ const hasSeparator = Boolean(withSep);
271
+ const headerRow = matches[2].trim();
272
+ const dataRows = (hasSeparator ? matches[4] : matches[3]).trim();
273
+ const headers = headerRow.split('|').map(cell => cell.trim()).slice(1, -1);
274
+ if (headers.length === 0)
275
+ return null;
276
+ const rows = dataRows
277
+ .split('\n')
278
+ .map(row => row.trim())
279
+ .filter(row => row.startsWith('|') && row.endsWith('|'))
280
+ .map(row => row.split('|').map(cell => cell.trim()).slice(1, -1))
281
+ .filter(row => row.length > 0);
282
+ if (rows.length === 0)
283
+ return null;
284
+ const maxCols = Math.max(headers.length, ...rows.map(row => row.length));
285
+ const paddedHeaders = [
286
+ ...headers,
287
+ ...Array(maxCols - headers.length).fill(''),
288
+ ];
289
+ const columns = paddedHeaders.map((header, idx) => ({
290
+ id: `col-${idx}`,
291
+ label: processCellContent(header),
292
+ dataField: `col-${idx}`,
293
+ render: (data) => processCellContent(data[`col-${idx}`] || ''),
294
+ }));
295
+ const tableData = rows.map((row, rowIdx) => {
296
+ const rowData = { id: `row-${rowIdx}` };
297
+ paddedHeaders.forEach((_, colIdx) => {
298
+ rowData[`col-${colIdx}`] = row[colIdx] || '';
299
+ });
300
+ return rowData;
301
+ });
302
+ return {
303
+ elem: (jsx(Table, { size: "s", variant: "plain", columns: columns, data: tableData, className: S.table })),
304
+ index: matches.index + (matches[1]?.length || 0),
305
+ length: matches[0].length - (matches[1]?.length || 0),
306
+ };
307
+ };
308
+ return (jsx("div", { className: className, children: applyInjectors(text, [
309
+ injectTables,
310
+ injectCodeBlock,
311
+ injectPrettyJson,
312
+ injectHeading,
313
+ injectLines,
314
+ injectLinks,
315
+ injectBold,
316
+ injectItalic,
317
+ injectBullet,
318
+ injectNumbered,
319
+ injectButtons,
320
+ ]) }));
321
+ }
322
+
323
+ export { ChatFormattedText };
@@ -0,0 +1,7 @@
1
+ import styleInject from '../../../node_modules/style-inject/dist/style-inject.es.js';
2
+
3
+ var css_248z = ".ChatFormattedText_bullet__CdKe7{display:inline-block;margin-bottom:2px;margin-left:var(--p-2);margin-right:2px}.ChatFormattedText_bullet__CdKe7:before{background-color:var(--accent-color);border-radius:50%;content:\"\";display:block;height:6px;margin:0 4px;width:6px}.ChatFormattedText_numberedIndex__bejS0{font-feature-settings:\"tnum\";color:var(--accent-color);display:inline-block;font-variant-numeric:tabular-nums;margin-left:var(--p-2);margin-right:6px;min-width:1.25em}.ChatFormattedText_line__1j8Sx{background-color:var(--accent-color-alpha-200);border-radius:2px;height:2px;margin:var(--p-2) 0;width:100%}.ChatFormattedText_codeBlock__Mm7Um,.ChatFormattedText_codeInline__gqRjp{background-color:var(--decent-color-alpha-400);border-radius:var(--p-2);box-shadow:0 1px 1px var(--accent-color-alpha-50),inset 0 1px 1px var(--decent-color-alpha-500);font-family:monospace;-webkit-user-select:text;-moz-user-select:text;user-select:text}.ChatFormattedText_codeInline__gqRjp{border-radius:3px;display:inline;font-size:90%;padding:0 4px}.ChatFormattedText_codeBlock__Mm7Um,.ChatFormattedText_jsonPre__m4NwI{display:block;font-size:90%;margin:var(--p-2) 0;overflow-x:auto;padding:var(--p-2);white-space:pre-wrap}.ChatFormattedText_jsonPre__m4NwI{background-color:var(--decent-color-alpha-300);border-radius:var(--p-2);box-shadow:0 1px 1px var(--accent-color-alpha-50),inset 0 1px 1px var(--accent-color-alpha-50);font-family:monospace;max-width:100%;-webkit-user-select:text;-moz-user-select:text;user-select:text}.ChatFormattedText_table__1rTGx{margin-bottom:10px}";
4
+ var S = {"bullet":"ChatFormattedText_bullet__CdKe7","numberedIndex":"ChatFormattedText_numberedIndex__bejS0","line":"ChatFormattedText_line__1j8Sx","codeInline":"ChatFormattedText_codeInline__gqRjp","codeBlock":"ChatFormattedText_codeBlock__Mm7Um","jsonPre":"ChatFormattedText_jsonPre__m4NwI","table":"ChatFormattedText_table__1rTGx"};
5
+ styleInject(css_248z);
6
+
7
+ export { S as default };
@@ -0,0 +1,50 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import cn from 'classnames';
3
+ import { useMemo } from 'react';
4
+ import { Expand } from '../Expand/Expand.js';
5
+ import { Link } from '../Router/Link/Link.js';
6
+ import { ChatFormattedText } from './ChatFormattedText.js';
7
+ import S from './ChatMessage.styl.js';
8
+ import { parseSystemEvent, getDisplayParts, getDisplayContent } from './content.js';
9
+
10
+ function ChatMessage({ data, isStacked, className, onButtonClick, }) {
11
+ const { content, role, createdAt } = data;
12
+ const id = data.id;
13
+ const isSystem = role === 'SYSTEM';
14
+ const date = createdAt ? new Date(createdAt) : null;
15
+ const systemEvent = useMemo(() => (isSystem ? parseSystemEvent(content) : null), [isSystem, content]);
16
+ const parts = useMemo(() => (isSystem ? null : getDisplayParts(content)), [content, isSystem]);
17
+ const body = useMemo(() => {
18
+ if (parts) {
19
+ return (jsx("div", { className: S.parts, children: parts.map((part, i) => {
20
+ if (part.type === 'text' && typeof part.text === 'string') {
21
+ return (jsx(ChatFormattedText, { text: part.text, onButtonClick: onButtonClick }, i));
22
+ }
23
+ if (part.type === 'image_url' && part.image_url?.url) {
24
+ return (jsx("img", { src: part.image_url.url, alt: "", className: S.mediaPart }, i));
25
+ }
26
+ if (part.type === 'video_url' && part.video_url?.url) {
27
+ return (jsx("video", { src: part.video_url.url, controls: true, className: S.mediaPart }, i));
28
+ }
29
+ if (part.type === 'file' && part.file?.url) {
30
+ return (jsx("div", { className: S.mediaPart, children: jsx(Link, { href: part.file.url, target: "_blank", rel: "noopener noreferrer", children: part.file.filename || 'Download' }) }, i));
31
+ }
32
+ if (part.type === 'input_audio' && part.input_audio?.data) {
33
+ const format = part.input_audio.format || 'mp3';
34
+ return (jsx("audio", { src: `data:audio/${format};base64,${part.input_audio.data}`, controls: true, className: S.mediaPart }, i));
35
+ }
36
+ return null;
37
+ }) }));
38
+ }
39
+ const text = isSystem
40
+ ? systemEvent?.body ?? content
41
+ : getDisplayContent(content);
42
+ return jsx(ChatFormattedText, { text: text, onButtonClick: onButtonClick });
43
+ }, [content, isSystem, onButtonClick, parts, systemEvent]);
44
+ return (jsxs("div", { className: cn(S.root, S[role], isStacked && S.stacked, className), "data-id": id, children: [date && !Number.isNaN(date.getTime()) && (jsx("div", { className: S.meta, children: date.toLocaleTimeString(undefined, {
45
+ hour: 'numeric',
46
+ minute: '2-digit',
47
+ }) })), jsx("div", { className: S.text, children: jsx("div", { className: S.textContent, children: isSystem ? (jsx(Expand, { className: S.systemFold, headerClassName: S.systemFoldTrigger, size: "s", isOpen: false, header: systemEvent?.summary || getDisplayContent(content), content: () => (jsx("div", { className: S.systemFoldContent, children: body })) })) : (body) }) })] }));
48
+ }
49
+
50
+ export { ChatMessage };
@@ -0,0 +1,7 @@
1
+ import styleInject from '../../../node_modules/style-inject/dist/style-inject.es.js';
2
+
3
+ var css_248z = ".ChatMessage_root__JkQi6{align-items:flex-start;display:flex;flex-direction:column;max-width:100%;padding:0 var(--p-5) var(--p-2)}@media (max-width:768px){.ChatMessage_root__JkQi6{padding:0 var(--p-2) var(--p-2)}}.ChatMessage_root__JkQi6+.ChatMessage_root__JkQi6{margin-top:20px}.ChatMessage_root__JkQi6 .ChatMessage_textContent__O-pxi{padding:0}.ChatMessage_root__JkQi6.ChatMessage_USER__UEEuA{align-items:flex-end;padding-right:var(--p-5)}.ChatMessage_root__JkQi6.ChatMessage_USER__UEEuA .ChatMessage_text__CNGXE{background-color:var(--active-color-alpha-500);padding:6px var(--p-2)}.ChatMessage_root__JkQi6.ChatMessage_AGENT__fvHxv .ChatMessage_textContent__O-pxi,.ChatMessage_root__JkQi6.ChatMessage_AGENT__fvHxv .ChatMessage_text__CNGXE{width:100%!important}.ChatMessage_root__JkQi6.ChatMessage_AGENT__fvHxv .ChatMessage_text__CNGXE{padding-top:4px}.ChatMessage_root__JkQi6.ChatMessage_SYSTEM__bkOnf{align-items:stretch}.ChatMessage_root__JkQi6.ChatMessage_SYSTEM__bkOnf+.ChatMessage_root__JkQi6.ChatMessage_SYSTEM__bkOnf{margin-top:-6px!important}.ChatMessage_root__JkQi6.ChatMessage_SYSTEM__bkOnf .ChatMessage_text__CNGXE{font-size:90%;opacity:.8;padding:0;width:100%}.ChatMessage_root__JkQi6.ChatMessage_stacked__LoLL0 .ChatMessage_meta__lMww1{display:none}.ChatMessage_text__CNGXE{border-radius:14px;display:flex;flex-direction:row;max-width:100%;overflow:hidden;padding:var(--p-2);width:-moz-fit-content;width:fit-content}.ChatMessage_textContent__O-pxi{max-width:100%;text-align:left;white-space:pre-line;word-break:break-word}.ChatMessage_textContent__O-pxi h1,.ChatMessage_textContent__O-pxi h2,.ChatMessage_textContent__O-pxi h3,.ChatMessage_textContent__O-pxi h4,.ChatMessage_textContent__O-pxi h5,.ChatMessage_textContent__O-pxi h6{margin-top:1em}.ChatMessage_textContent__O-pxi a{margin-bottom:-.1em;margin-top:-.3em;padding:0 .3em .1em .4em!important}.ChatMessage_SYSTEM__bkOnf .ChatMessage_textContent__O-pxi a{margin-bottom:0;margin-top:0}.ChatMessage_meta__lMww1{font-size:11px;margin-bottom:4px;opacity:.5;padding:0 4px}.ChatMessage_parts__z7LHI{display:flex;flex-direction:column;gap:var(--p-2)}.ChatMessage_mediaPart__A67rQ{border-radius:var(--p-2);max-height:320px;max-width:100%}.ChatMessage_systemFold__FUSrL{width:100%}.ChatMessage_systemFoldTrigger__35Hnd{max-width:100%;overflow:hidden;padding:2px 10px;text-overflow:ellipsis;white-space:nowrap}.ChatMessage_systemFoldContent__0G-uw{padding:0 10px}";
4
+ var S = {"root":"ChatMessage_root__JkQi6","textContent":"ChatMessage_textContent__O-pxi","USER":"ChatMessage_USER__UEEuA","text":"ChatMessage_text__CNGXE","AGENT":"ChatMessage_AGENT__fvHxv","SYSTEM":"ChatMessage_SYSTEM__bkOnf","stacked":"ChatMessage_stacked__LoLL0","meta":"ChatMessage_meta__lMww1","parts":"ChatMessage_parts__z7LHI","mediaPart":"ChatMessage_mediaPart__A67rQ","systemFold":"ChatMessage_systemFold__FUSrL","systemFoldTrigger":"ChatMessage_systemFoldTrigger__35Hnd","systemFoldContent":"ChatMessage_systemFoldContent__0G-uw"};
5
+ styleInject(css_248z);
6
+
7
+ export { S as default };
@@ -0,0 +1,50 @@
1
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
+ import cn from 'classnames';
3
+ import { useRef, useState } from 'react';
4
+ import { Button } from '../Button/Button.js';
5
+ import { Icon } from '../Icon/Icon.js';
6
+ import { PromptComposer } from '../PromptComposer/PromptComposer.js';
7
+ import { Select2 } from '../Select/Select2.js';
8
+ import { ThinkingOutline } from '../ThinkingOutline/ThinkingOutline.js';
9
+ import { Tooltip } from '../Tooltip/Tooltip.js';
10
+ import S from './ChatPrompt.styl.js';
11
+
12
+ const DEFAULT_MODELS = [
13
+ { id: 'auto', label: 'Auto Router' },
14
+ ];
15
+ function ChatPrompt({ value, onChange, onSubmit, disabled, isPrompting, placeholder = 'Message', className, showAttach = true, onAttach, attachAccept, showModelSelector = true, models = DEFAULT_MODELS, model, onModelChange, }) {
16
+ const fileInputRef = useRef(null);
17
+ const [uncontrolledModel, setUncontrolledModel] = useState(model ?? models[0]?.id ?? 'auto');
18
+ const modelId = model ?? uncontrolledModel;
19
+ const canSubmit = !disabled && Boolean(value.trim());
20
+ const setModel = (id) => {
21
+ if (model === undefined)
22
+ setUncontrolledModel(id);
23
+ onModelChange?.(id);
24
+ };
25
+ return (jsxs("div", { className: cn(S.root, className), children: [jsx(ThinkingOutline, { active: isPrompting }), jsx(PromptComposer, { className: S.composer, disabled: disabled, placeholder: placeholder, prefillMessage: value, allowEnterSubmit: true, onChange: onChange, onSubmit: text => {
26
+ const next = text.trim();
27
+ if (!next || disabled)
28
+ return;
29
+ onSubmit(next);
30
+ } }), jsxs("div", { className: S.buttons, children: [jsx(Button, { className: cn(S.button, S.submit), variant: "text", type: "submit", round: true, square: true, disabled: !canSubmit, "aria-label": "Send", onClick: () => {
31
+ const next = value.trim();
32
+ if (!next || disabled)
33
+ return;
34
+ onSubmit(next);
35
+ }, children: jsx(Icon, { type: "arrowUp", className: S.submitIcon }) }), showModelSelector && (jsx(Select2, { className: S.promptModelSelector, label: "", size: "s", disableLabel: true, hideRequiredStar: true, round: true, options: models, value: modelId, disabled: disabled, popupProps: {
36
+ direction: 'top-right',
37
+ round: true,
38
+ }, onChange: next => {
39
+ if (next == null || Array.isArray(next))
40
+ return;
41
+ setModel(String(next));
42
+ } })), jsx("div", { className: S.gap }), showAttach && (jsxs(Fragment, { children: [jsx("input", { ref: fileInputRef, type: "file", accept: attachAccept, multiple: true, className: S.fileInput, disabled: disabled, onChange: e => {
43
+ const files = e.target.files;
44
+ if (files?.length)
45
+ onAttach?.(Array.from(files));
46
+ e.target.value = '';
47
+ } }), jsx(Tooltip, { content: "Attach", direction: "right", children: jsx(Button, { variant: "text", className: S.attachButton, disabled: disabled, "aria-label": "Attach", onClick: () => fileInputRef.current?.click(), children: jsx(Icon, { size: "m", type: "plus" }) }) })] }))] })] }));
48
+ }
49
+
50
+ export { ChatPrompt };
@@ -0,0 +1,7 @@
1
+ import styleInject from '../../../node_modules/style-inject/dist/style-inject.es.js';
2
+
3
+ var css_248z = ".ChatPrompt_root__jEydp{-webkit-backdrop-filter:blur(20px);backdrop-filter:blur(20px);background-color:var(--decent-color-alpha-500);background-color:var(--accent-color-alpha-50);border-radius:var(--p-5);box-shadow:0 0 0 1px var(--active-color-alpha-100);display:flex;flex-direction:column;flex-wrap:wrap;font-size:80%;font-size:calc(80%*var(--dialogue-text-scale, 1));margin:2px auto;max-width:600px;min-height:76px;min-height:calc(var(--prompt-height, 80px) - 4px);position:relative;transition:box-shadow .4s ease-out,border-top-left-radius .2s ease,border-top-right-radius .2s ease,background-color .5s ease;width:100%}.ChatPrompt_root__jEydp:after{border-radius:inherit;box-shadow:inset 0 0 0 1px var(--accent-color-alpha-100),0 0 0 2px var(--decent-color-alpha-800),0 0 30px 0 var(--decent-color-alpha-500);content:\"\";height:100%;left:0;pointer-events:none;position:absolute;top:0;transition:box-shadow .4s ease-out;width:100%;z-index:-2}.ChatPrompt_root__jEydp:focus-within:after,.ChatPrompt_root__jEydp:hover:after{box-shadow:0 0 0 2px var(--decent-color-alpha-500),0 0 50px 0 var(--decent-color-alpha-500)}.ChatPrompt_root__jEydp:focus-within,.ChatPrompt_root__jEydp:hover{box-shadow:inset 0 0 0 1px var(--decent-color-alpha-500)}.ChatPrompt_root__jEydp:hover{box-shadow:inset 0 0 0 1px var(--active-color-alpha-300)}.ChatPrompt_root__jEydp:focus-within{box-shadow:inset 0 0 0 1px var(--active-color-alpha-500)}.ChatPrompt_composer__uWvF4{background-color:transparent!important;position:relative;transition:opacity .2s ease-out;width:100%;z-index:1}.ChatPrompt_composer__uWvF4 .ProseMirror,.ChatPrompt_composer__uWvF4 .editorMount .promptComposerEditor{caret-color:var(--accent-color);font-size:16px!important;font-size:calc(16px*var(--dialogue-text-scale, 1))!important;min-height:1.5em!important;padding:10px var(--p-7) 0 14px!important}.ChatPrompt_composer__uWvF4 .ProseMirror:focus{box-shadow:inset 0 0 0 2px none}.ChatPrompt_composer__uWvF4 .promptComposerEmptyEditor .promptComposerEmptyNode:before{color:var(--accent-color-alpha-500)}.ChatPrompt_buttons__gm2Lm{align-items:center;cursor:text;display:flex;flex-direction:row-reverse;flex-shrink:0;flex-wrap:wrap;gap:6px;justify-content:flex-start;padding:0 2px 0 6px;transform:translateY(-2px);width:100%;z-index:1}.ChatPrompt_buttons__gm2Lm svg{transition:.2s ease-out;transition-property:filter,scale}.ChatPrompt_button__h1lLp{background-color:transparent!important;padding:0 var(--p-2);position:relative}.ChatPrompt_button__h1lLp:focus,.ChatPrompt_button__h1lLp:hover{opacity:1}.ChatPrompt_button__h1lLp.ChatPrompt_submit__CICZy{background-color:var(--active-color)!important;box-shadow:0 1px 1px 0 rgba(0,0,0,.6);color:var(--decent-color)!important;margin-left:var(--p-2);transition:filter .2s ease-out,opacity .5s ease-out}.ChatPrompt_button__h1lLp.ChatPrompt_submit__CICZy svg{color:var(--decent-color)!important}.ChatPrompt_button__h1lLp.ChatPrompt_submit__CICZy:focus,.ChatPrompt_button__h1lLp.ChatPrompt_submit__CICZy:focus-visible,.ChatPrompt_button__h1lLp.ChatPrompt_submit__CICZy:hover{filter:drop-shadow(0 0 14px var(--active-color))}.ChatPrompt_button__h1lLp.ChatPrompt_submit__CICZy[disabled]{background-color:inherit!important;box-shadow:none;filter:none;pointer-events:none}.ChatPrompt_button__h1lLp.ChatPrompt_submit__CICZy[disabled] svg{color:var(--accent-color-alpha-500)!important}.ChatPrompt_submitIcon__yqHzk{display:block}.ChatPrompt_gap__xkA50{flex-grow:1}.ChatPrompt_promptModelSelector__RZpMR{flex-shrink:0;max-width:calc(100% - 200px);opacity:.5;transition:opacity .2s ease-out}.ChatPrompt_promptModelSelector__RZpMR:hover{opacity:1}.ChatPrompt_fileInput__l36Lj{display:none}.ChatPrompt_attachButton__vLVfy{flex-shrink:0;margin-left:-8px;opacity:.5;position:relative;z-index:4}";
4
+ var S = {"root":"ChatPrompt_root__jEydp","composer":"ChatPrompt_composer__uWvF4","buttons":"ChatPrompt_buttons__gm2Lm","button":"ChatPrompt_button__h1lLp","submit":"ChatPrompt_submit__CICZy","submitIcon":"ChatPrompt_submitIcon__yqHzk","gap":"ChatPrompt_gap__xkA50","promptModelSelector":"ChatPrompt_promptModelSelector__RZpMR","fileInput":"ChatPrompt_fileInput__l36Lj","attachButton":"ChatPrompt_attachButton__vLVfy"};
5
+ styleInject(css_248z);
6
+
7
+ export { S as default };
@@ -0,0 +1,30 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import cn from 'classnames';
3
+ import { useRef, useEffect } from 'react';
4
+ import { Scroll } from '../Scroll/Scroll.js';
5
+ import { TextShimmer } from '../TextShimmer/TextShimmer.js';
6
+ import { scrollTo } from '../../tools/scroll.js';
7
+ import { ChatMessage } from './ChatMessage.js';
8
+ import S from './ChatView.styl.js';
9
+ import { isPlanMessageContent } from './content.js';
10
+
11
+ function ChatView({ messages, isPrompting, promptingLabel = 'Thinking…', emptyLabel = 'Start the conversation', className, messagesClassName, footer, onButtonClick, }) {
12
+ const listRef = useRef(null);
13
+ const visible = messages.filter(message => !isPlanMessageContent(message.content));
14
+ useEffect(() => {
15
+ const scroller = listRef.current;
16
+ if (scroller)
17
+ scrollTo(scroller, 0, scroller.scrollHeight + 80);
18
+ }, [visible.length, isPrompting]);
19
+ return (jsxs("div", { className: cn(S.root, className), children: [jsxs(Scroll, { y: true, fadeSize: "l", autoHide: true, className: S.messages, innerClassName: cn(S.messagesInner, messagesClassName), onInnerRef: elem => {
20
+ listRef.current = elem;
21
+ }, children: [visible.length === 0 && jsx("div", { className: S.empty, children: emptyLabel }), visible.map((message, index) => {
22
+ const prev = visible[index - 1];
23
+ const isStacked = Boolean(prev) &&
24
+ prev.role === message.role &&
25
+ message.role !== 'SYSTEM';
26
+ return (jsx(ChatMessage, { data: message, isStacked: isStacked, isLastMessage: index === visible.length - 1, onButtonClick: onButtonClick }, message.id || `${message.role}-${index}`));
27
+ })] }), isPrompting && (jsx("div", { className: S.status, children: jsx(TextShimmer, { children: promptingLabel }) })), footer && jsx("div", { className: S.footer, children: footer })] }));
28
+ }
29
+
30
+ export { ChatView };
@@ -0,0 +1,7 @@
1
+ import styleInject from '../../../node_modules/style-inject/dist/style-inject.es.js';
2
+
3
+ var css_248z = ".ChatView_root__fRLUe{display:flex;flex-direction:column;height:100%;min-height:0;width:100%}.ChatView_messages__XjC53{flex:1;min-height:0}.ChatView_messagesInner__oRfmN{display:flex;flex-direction:column;padding:var(--p-10) calc(50% - 300px) 0}.ChatView_empty__5yGXV{margin:auto;opacity:.6;padding:24px;text-align:center}.ChatView_status__PpDvZ{font-size:13px;padding:4px 8px 0}.ChatView_footer__huDww{flex-shrink:0;overflow:visible;padding-top:0}";
4
+ var S = {"root":"ChatView_root__fRLUe","messages":"ChatView_messages__XjC53","messagesInner":"ChatView_messagesInner__oRfmN","empty":"ChatView_empty__5yGXV","status":"ChatView_status__PpDvZ","footer":"ChatView_footer__huDww"};
5
+ styleInject(css_248z);
6
+
7
+ export { S as default };
@@ -0,0 +1,96 @@
1
+ const PLAN_TYPES = new Set([
2
+ 'planCreated',
3
+ 'planStatusUpdate',
4
+ 'planStepUpdate',
5
+ 'planStepChunk',
6
+ ]);
7
+ function isPlanMessageContent(content) {
8
+ try {
9
+ const parsed = JSON.parse(content);
10
+ if (parsed.planId)
11
+ return true;
12
+ if (typeof parsed.type === 'string' && PLAN_TYPES.has(parsed.type)) {
13
+ return true;
14
+ }
15
+ }
16
+ catch {
17
+ // plain text
18
+ }
19
+ return false;
20
+ }
21
+ function getDisplayContent(content) {
22
+ try {
23
+ const parsed = JSON.parse(content);
24
+ if (parsed.type === 'userPrompt' && typeof parsed.display === 'string') {
25
+ return parsed.display;
26
+ }
27
+ if (Array.isArray(parsed.parts)) {
28
+ return parsed.parts
29
+ .filter(part => part.type === 'text' && typeof part.text === 'string')
30
+ .map(part => part.text)
31
+ .join('\n');
32
+ }
33
+ }
34
+ catch {
35
+ // plain text
36
+ }
37
+ return content;
38
+ }
39
+ function getDisplayParts(content) {
40
+ try {
41
+ const parsed = JSON.parse(content);
42
+ if (Array.isArray(parsed.parts) && parsed.parts.length > 0) {
43
+ return parsed.parts;
44
+ }
45
+ }
46
+ catch {
47
+ // plain text
48
+ }
49
+ return null;
50
+ }
51
+ function parseSystemEvent(content) {
52
+ try {
53
+ const parsed = JSON.parse(content);
54
+ if (parsed.systemEventType && parsed.systemData) {
55
+ switch (parsed.systemEventType) {
56
+ case 'agent-selected':
57
+ return {
58
+ summary: `Agent switched to: ${parsed.systemData.agentId || 'Auto'}`,
59
+ body: content,
60
+ };
61
+ case 'function-call':
62
+ return {
63
+ summary: `Called function: ${parsed.systemData.functionName}`,
64
+ body: content,
65
+ };
66
+ case 'error':
67
+ return {
68
+ summary: `Error: ${parsed.systemData.errorMessage}`,
69
+ body: content,
70
+ };
71
+ case 'conversation-stopped':
72
+ return { summary: 'Conversation stopped', body: content };
73
+ default:
74
+ return { summary: parsed.systemEventType, body: content };
75
+ }
76
+ }
77
+ if (parsed.type === 'toolInvocation' && parsed.name) {
78
+ if (parsed.phase === 'invoked') {
79
+ return { summary: `Calling ${parsed.name}…`, body: content };
80
+ }
81
+ if (parsed.ok === false) {
82
+ return {
83
+ summary: `${parsed.name} failed${parsed.error ? `: ${parsed.error}` : ''}`,
84
+ body: content,
85
+ };
86
+ }
87
+ return { summary: `${parsed.name} result`, body: content };
88
+ }
89
+ }
90
+ catch {
91
+ // not structured
92
+ }
93
+ return null;
94
+ }
95
+
96
+ export { getDisplayContent, getDisplayParts, isPlanMessageContent, parseSystemEvent };
@@ -16,8 +16,10 @@ function Dialogue({ open, onOpenChange, disabled, trigger, title, subtitle, icon
16
16
  const [isMounted, setIsMounted] = useState(false);
17
17
  const [isAnimating, setIsAnimating] = useState(false);
18
18
  const dialogRef = useRef(null);
19
+ const onOpenChangeRef = useRef(onOpenChange);
19
20
  const titleId = useId();
20
21
  const descriptionId = useId();
22
+ onOpenChangeRef.current = onOpenChange;
21
23
  useEffect(() => {
22
24
  setIsMounted(true);
23
25
  }, []);
@@ -49,7 +51,7 @@ function Dialogue({ open, onOpenChange, disabled, trigger, title, subtitle, icon
49
51
  }
50
52
  const handleKeyDown = (e) => {
51
53
  if (e.key === 'Escape') {
52
- onOpenChange(false);
54
+ onOpenChangeRef.current(false);
53
55
  return;
54
56
  }
55
57
  if (e.key === 'Tab' && focusableElements.length > 0) {
@@ -72,7 +74,7 @@ function Dialogue({ open, onOpenChange, disabled, trigger, title, subtitle, icon
72
74
  previousActiveElement.focus();
73
75
  }
74
76
  };
75
- }, [open, onOpenChange]);
77
+ }, [open]);
76
78
  useEffect(() => {
77
79
  if (!open)
78
80
  return;
@@ -32,6 +32,17 @@ import '../Checkbox/Checkbox.styl.js';
32
32
  import '../Chip/Chip.styl.js';
33
33
  import '../Tooltip/Tooltip.js';
34
34
  import '../Card/Card.js';
35
+ import '../Router/context.js';
36
+ import '../Router/Link/Link.styl.js';
37
+ import '../Table/Table.styl.js';
38
+ import '../Chat/ChatFormattedText.styl.js';
39
+ import '../Expand/Expand.styl.js';
40
+ import '../Chat/ChatMessage.styl.js';
41
+ import '../PromptComposer/PromptComposer.js';
42
+ import '../ThinkingOutline/ThinkingOutline.styl.js';
43
+ import '../Chat/ChatPrompt.styl.js';
44
+ import '../TextShimmer/TextShimmer.js';
45
+ import '../Chat/ChatView.styl.js';
35
46
  import '../Container/Container.js';
36
47
  import '../DatePicker/DatePicker.styl.js';
37
48
  import 'moment';
@@ -39,7 +50,6 @@ import '../DatePickerInput/DatePickerInput.styl.js';
39
50
  import '../Dialogue/Dialogue.js';
40
51
  import { Draggable } from '../Draggable/Draggable.js';
41
52
  import '../DropZone/DropZone.styl.js';
42
- import '../Expand/Expand.styl.js';
43
53
  import '../Flex/Flex.styl.js';
44
54
  import '../Form/Form.styl.js';
45
55
  import '../Form/Validator.js';
@@ -59,7 +69,6 @@ import '../Notifications/store.js';
59
69
  import '../Notifications/Notifications.styl.js';
60
70
  import '../PopupMenu/PopupMenu.styl.js';
61
71
  import '../Progress/Progress.styl.js';
62
- import '../PromptComposer/PromptComposer.js';
63
72
  import '@tiptap/extensions';
64
73
  import '@tiptap/react';
65
74
  import '@tiptap/starter-kit';
@@ -72,9 +81,7 @@ import '../RadioGroup/RadioGroupContext.js';
72
81
  import '../RadioButton/RadioButton.styl.js';
73
82
  import '../RadioGroup/RadioGroup.styl.js';
74
83
  import '../Router/Router.js';
75
- import '../Table/Table.styl.js';
76
84
  import '../Tabs/Tabs.styl.js';
77
- import '../TextShimmer/TextShimmer.js';
78
85
  import '../TextWithDeferTooltip/TextWithDeferTooltip.styl.js';
79
86
  import '../Text/Text.js';
80
87
  import '../Theme/Theme.defaults.js';
@@ -0,0 +1,9 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import cn from 'classnames';
3
+ import S from './ThinkingOutline.styl.js';
4
+
5
+ function ThinkingOutline({ active, className }) {
6
+ return (jsx("div", { className: cn(S.root, active && S.active, className), children: jsx("div", { className: S.bloom }) }));
7
+ }
8
+
9
+ export { ThinkingOutline };
@@ -0,0 +1,7 @@
1
+ import styleInject from '../../../node_modules/style-inject/dist/style-inject.es.js';
2
+
3
+ var css_248z = "@property --promptGlowAngle{syntax:\"<angle>\";inherits:true;initial-value:0deg}.ThinkingOutline_root__rvvBG{animation:ThinkingOutline_orbitGlow__3bK-F 3.5s linear infinite;border-radius:inherit;inset:0;opacity:0;pointer-events:none;position:absolute;transition:opacity .5s ease-out}.ThinkingOutline_root__rvvBG.ThinkingOutline_active__-66iV{opacity:1}.ThinkingOutline_root__rvvBG:before{background:conic-gradient(from var(--promptGlowAngle),var(--active-color) 0deg,var(--active-color-alpha-300) 48deg,transparent 80deg,transparent 100deg,var(--active-color-alpha-300) 132deg,var(--active-color) 180deg,var(--active-color-alpha-300) 228deg,transparent 260deg,transparent 280deg,var(--active-color-alpha-300) 312deg,var(--active-color) 1turn);border-radius:inherit;content:\"\";inset:0;-webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);-webkit-mask-composite:xor;mask-composite:exclude;padding:1.5px;position:absolute}.ThinkingOutline_bloom__XKYD5{border-radius:inherit;filter:blur(20px);inset:0;opacity:.55;position:absolute}.ThinkingOutline_bloom__XKYD5:before{background:conic-gradient(from var(--promptGlowAngle),var(--active-color) 0deg,var(--active-color-alpha-300) 48deg,transparent 80deg,transparent 100deg,var(--active-color-alpha-300) 132deg,var(--active-color) 180deg,var(--active-color-alpha-300) 228deg,transparent 260deg,transparent 280deg,var(--active-color-alpha-300) 312deg,var(--active-color) 1turn);border-radius:inherit;content:\"\";inset:0;-webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);-webkit-mask-composite:xor;mask-composite:exclude;padding:6px;position:absolute}@media (prefers-reduced-motion:reduce){.ThinkingOutline_root__rvvBG{animation:none}}@keyframes ThinkingOutline_orbitGlow__3bK-F{0%{--promptGlowAngle:-30deg}25%{--promptGlowAngle:30deg}50%{--promptGlowAngle:150deg}75%{--promptGlowAngle:210deg}to{--promptGlowAngle:330deg}}";
4
+ var S = {"root":"ThinkingOutline_root__rvvBG","orbitGlow":"ThinkingOutline_orbitGlow__3bK-F","active":"ThinkingOutline_active__-66iV","bloom":"ThinkingOutline_bloom__XKYD5"};
5
+ styleInject(css_248z);
6
+
7
+ export { S as default };
@@ -0,0 +1,78 @@
1
+ import type { ReactNode } from 'react';
2
+ export type ChatRole = 'USER' | 'AGENT' | 'SYSTEM';
3
+ export type ChatContentPart = {
4
+ type: string;
5
+ text?: string;
6
+ image_url?: {
7
+ url?: string;
8
+ filePath?: string;
9
+ filename?: string;
10
+ };
11
+ video_url?: {
12
+ url?: string;
13
+ filePath?: string;
14
+ };
15
+ file?: {
16
+ url?: string;
17
+ filePath?: string;
18
+ filename?: string;
19
+ };
20
+ input_audio?: {
21
+ data?: string;
22
+ format?: string;
23
+ };
24
+ };
25
+ export type ChatMessageData = {
26
+ id?: string;
27
+ role: ChatRole;
28
+ content: string;
29
+ createdAt?: string | Date;
30
+ };
31
+ export type ChatFormattedTextProps = {
32
+ text: string;
33
+ className?: string;
34
+ onButtonClick?: (params: {
35
+ text: string;
36
+ [name: string]: string;
37
+ }) => void;
38
+ };
39
+ export type ChatMessageProps = {
40
+ data: ChatMessageData;
41
+ isStacked?: boolean;
42
+ isLastMessage?: boolean;
43
+ className?: string;
44
+ onButtonClick?: ChatFormattedTextProps['onButtonClick'];
45
+ };
46
+ export type ChatViewProps = {
47
+ messages: ChatMessageData[];
48
+ isPrompting?: boolean;
49
+ promptingLabel?: ReactNode;
50
+ emptyLabel?: ReactNode;
51
+ className?: string;
52
+ messagesClassName?: string;
53
+ footer?: ReactNode;
54
+ onButtonClick?: ChatFormattedTextProps['onButtonClick'];
55
+ };
56
+ export type ChatPromptModel = {
57
+ id: string;
58
+ label: string;
59
+ };
60
+ export type ChatPromptProps = {
61
+ value: string;
62
+ onChange: (value: string) => void;
63
+ onSubmit: (value: string) => void;
64
+ disabled?: boolean;
65
+ /** Orbiting glow on the prompt while the agent is generating. */
66
+ isPrompting?: boolean;
67
+ placeholder?: string;
68
+ className?: string;
69
+ /** Default true. Hidden file input + plus button (no STT / live voice). */
70
+ showAttach?: boolean;
71
+ onAttach?: (files: File[]) => void;
72
+ attachAccept?: string;
73
+ /** Default true. Compact model dropdown (e.g. Auto Router). */
74
+ showModelSelector?: boolean;
75
+ models?: ChatPromptModel[];
76
+ model?: string;
77
+ onModelChange?: (id: string) => void;
78
+ };
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ import type { ChatFormattedTextProps } from './types';
3
+ export declare function ChatFormattedText({ text, className, onButtonClick, }: ChatFormattedTextProps): React.JSX.Element;
@@ -0,0 +1,2 @@
1
+ import type { ChatMessageProps } from './types';
2
+ export declare function ChatMessage({ data, isStacked, className, onButtonClick, }: ChatMessageProps): import("react").JSX.Element;
@@ -0,0 +1,2 @@
1
+ import type { ChatPromptProps } from './types';
2
+ export declare function ChatPrompt({ value, onChange, onSubmit, disabled, isPrompting, placeholder, className, showAttach, onAttach, attachAccept, showModelSelector, models, model, onModelChange, }: ChatPromptProps): import("react").JSX.Element;
@@ -0,0 +1,2 @@
1
+ import type { ChatViewProps } from './types';
2
+ export declare function ChatView({ messages, isPrompting, promptingLabel, emptyLabel, className, messagesClassName, footer, onButtonClick, }: ChatViewProps): import("react").JSX.Element;
@@ -0,0 +1,8 @@
1
+ import type { ChatContentPart } from './types';
2
+ export declare function isPlanMessageContent(content: string): boolean;
3
+ export declare function getDisplayContent(content: string): string;
4
+ export declare function getDisplayParts(content: string): ChatContentPart[] | null;
5
+ export declare function parseSystemEvent(content: string): {
6
+ summary: string;
7
+ body: string;
8
+ } | null;
@@ -0,0 +1,6 @@
1
+ export { ChatFormattedText } from './ChatFormattedText';
2
+ export { ChatMessage } from './ChatMessage';
3
+ export { ChatPrompt } from './ChatPrompt';
4
+ export { ChatView } from './ChatView';
5
+ export { getDisplayContent, getDisplayParts, isPlanMessageContent, parseSystemEvent, } from './content';
6
+ export type { ChatContentPart, ChatFormattedTextProps, ChatMessageData, ChatMessageProps, ChatPromptModel, ChatPromptProps, ChatRole, ChatViewProps, } from './types';
@@ -0,0 +1 @@
1
+ export type { ChatContentPart, ChatFormattedTextProps, ChatMessageData, ChatMessageProps, ChatPromptModel, ChatPromptProps, ChatRole, ChatViewProps, } from './Chat.types';
@@ -1,5 +1,4 @@
1
1
  import * as T from './NestedMenu.types';
2
- export type { NestedMenuItem, Props as NestedMenuProps, } from './NestedMenu.types';
3
2
  export declare function NestedMenuLabel({ children, className }: T.NestedMenuLabelProps): import("react").JSX.Element;
4
3
  export declare function NestedMenuItemRow({ children, className, danger, disabled, href, target, rel, onClick, }: T.NestedMenuRowProps): import("react").JSX.Element;
5
4
  declare function NestedMenuComponent({ trigger, items, open, onOpenChange, align, className, }: T.Props): import("react").JSX.Element;
@@ -7,3 +6,4 @@ export declare const NestedMenu: typeof NestedMenuComponent & {
7
6
  Item: typeof NestedMenuItemRow;
8
7
  Label: typeof NestedMenuLabel;
9
8
  };
9
+ export {};
@@ -19,6 +19,7 @@ export type Props = {
19
19
  align?: 'start' | 'end';
20
20
  className?: string;
21
21
  };
22
+ export type NestedMenuProps = Props;
22
23
  export type NestedMenuRowProps = {
23
24
  children: ReactNode;
24
25
  className?: string;
@@ -0,0 +1,5 @@
1
+ export type ThinkingOutlineProps = {
2
+ active?: boolean;
3
+ className?: string;
4
+ };
5
+ export declare function ThinkingOutline({ active, className }: ThinkingOutlineProps): import("react").JSX.Element;
@@ -0,0 +1,2 @@
1
+ export { ThinkingOutline } from './ThinkingOutline';
2
+ export type { ThinkingOutlineProps } from './ThinkingOutline';
@@ -6,6 +6,7 @@ export * from './Calendar/Calendar';
6
6
  export * from './Checkbox/Checkbox';
7
7
  export * from './Chip/Chip';
8
8
  export * from './Card';
9
+ export * from './Chat';
9
10
  export * from './Container/Container';
10
11
  export * from './DatePicker/DatePicker';
11
12
  export * from './DatePickerInput/DatePickerInput';
@@ -29,6 +30,7 @@ export * from './Lazy/Lazy';
29
30
  export * from './LightBox/LightBox';
30
31
  export * from './Menu/Menu';
31
32
  export * from './NestedMenu/NestedMenu';
33
+ export type { NestedMenuItem, NestedMenuProps, } from './NestedMenu/NestedMenu.types';
32
34
  export * from './Notifications/Notifications';
33
35
  export * from './Paranja/Paranja';
34
36
  export * from './Popup/Popup';
@@ -50,6 +52,7 @@ export * from './Spinner/Spinner';
50
52
  export * from './Table/Table';
51
53
  export * from './Tabs/Tabs';
52
54
  export * from './TextShimmer/TextShimmer';
55
+ export * from './ThinkingOutline';
53
56
  export * from './TextWithDeferTooltip';
54
57
  export * from './Tooltip/Tooltip';
55
58
  export * from './Text/Text';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@homecode/ui",
3
- "version": "5.8.0",
3
+ "version": "5.9.0",
4
4
  "description": "React UI components library",
5
5
  "scripts": {
6
6
  "tests": "jest",