@lvce-editor/chat-view 6.64.0 → 6.65.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.
@@ -1865,7 +1865,8 @@ const StartConversationByTypingBelow = 'Start a conversation by typing below.';
1865
1865
  const NoMatchingModelsFound = 'No matching models have been found.';
1866
1866
  const ComposePlaceholder = 'Type your message. Enter to send.';
1867
1867
  const AttachImageAsContext = 'Attach Image as Context';
1868
- const RemoveImageAttachment = 'Remove image attachment';
1868
+ const OpenImageInNewTab = 'Open image in new tab';
1869
+ const RemoveAttachment = 'Remove attachment';
1869
1870
  const ImageCouldNotBeLoaded = 'image could not be loaded';
1870
1871
  const OpenRouterApiKeyPlaceholder = 'Enter OpenRouter API key';
1871
1872
  const OpenApiApiKeyPlaceholder = 'Enter OpenAI API key';
@@ -1960,8 +1961,11 @@ const composePlaceholder = () => {
1960
1961
  const attachImageAsContext = () => {
1961
1962
  return i18nString(AttachImageAsContext);
1962
1963
  };
1963
- const removeImageAttachment = () => {
1964
- return i18nString(RemoveImageAttachment);
1964
+ const openImageInNewTab = () => {
1965
+ return i18nString(OpenImageInNewTab);
1966
+ };
1967
+ const removeAttachment = () => {
1968
+ return i18nString(RemoveAttachment);
1965
1969
  };
1966
1970
  const imageCouldNotBeLoaded = () => {
1967
1971
  return i18nString(ImageCouldNotBeLoaded);
@@ -3245,6 +3249,24 @@ const getKeyBindings = () => {
3245
3249
  }];
3246
3250
  };
3247
3251
 
3252
+ const getMenuEntriesChatAttachment = (attachmentId, previewSrc) => {
3253
+ return [{
3254
+ args: [previewSrc],
3255
+ command: 'Chat.openChatAttachmentInNewTab',
3256
+ flags: None,
3257
+ id: 'openImageInNewTab',
3258
+ // @ts-ignore
3259
+ label: openImageInNewTab()
3260
+ }, {
3261
+ args: [attachmentId],
3262
+ command: 'Chat.removeComposerAttachment',
3263
+ flags: None,
3264
+ id: 'removeAttachment',
3265
+ // @ts-ignore
3266
+ label: removeAttachment()
3267
+ }];
3268
+ };
3269
+
3248
3270
  const getMenuEntriesChatHeader = () => {
3249
3271
  // TODO
3250
3272
  return [{
@@ -3304,6 +3326,7 @@ const Composer = 'composer';
3304
3326
  const Search = 'search';
3305
3327
  const ComposerDropTarget = 'composer-drop-target';
3306
3328
  const ComposerAttachmentPrefix = 'composer-attachment:';
3329
+ const ComposerAttachmentPreviewPrefix = 'composer-attachment-preview:';
3307
3330
  const ComposerAttachmentRemovePrefix = 'composer-attachment-remove:';
3308
3331
  const AddContext = 'add-context';
3309
3332
  const Dictate = 'dictate';
@@ -3377,6 +3400,12 @@ const getComposerAttachmentInputName = attachmentId => {
3377
3400
  const getComposerAttachmentRemoveInputName = attachmentId => {
3378
3401
  return `${ComposerAttachmentRemovePrefix}${attachmentId}`;
3379
3402
  };
3403
+ const isComposerAttachmentPreviewInputName = name => {
3404
+ return name.startsWith(ComposerAttachmentPreviewPrefix);
3405
+ };
3406
+ const getAttachmentIdFromComposerAttachmentPreviewInputName = name => {
3407
+ return name.slice(ComposerAttachmentPreviewPrefix.length);
3408
+ };
3380
3409
  const isComposerAttachmentRemoveInputName = name => {
3381
3410
  return name.startsWith(ComposerAttachmentRemovePrefix);
3382
3411
  };
@@ -3452,12 +3481,15 @@ const MenuChatHeader = 2179;
3452
3481
  const MenuChatInput = 2180;
3453
3482
  const MenuProjectAddButton = 2181;
3454
3483
  const MenuChatProjectList = 2182;
3484
+ const MenuChatAttachment = 2183;
3455
3485
  const getMenuEntryIds = () => {
3456
- return [Chat$2, MenuChatList, MenuChatHeader, MenuChatInput, MenuProjectAddButton, MenuChatProjectList];
3486
+ return [Chat$2, MenuChatList, MenuChatHeader, MenuChatInput, MenuProjectAddButton, MenuChatProjectList, MenuChatAttachment];
3457
3487
  };
3458
3488
 
3459
3489
  const getMenuEntries = (menuId, props) => {
3460
3490
  switch (props.menuId) {
3491
+ case MenuChatAttachment:
3492
+ return getMenuEntriesChatAttachment(props.attachmentId, props.previewSrc);
3461
3493
  case MenuChatHeader:
3462
3494
  return getMenuEntriesChatHeader();
3463
3495
  case MenuChatInput:
@@ -6528,6 +6560,7 @@ const ChatOverlays = 'ChatOverlays';
6528
6560
  const ChatOrderedList = 'ChatOrderedList';
6529
6561
  const ChatOrderedListItem = 'ChatOrderedListItem';
6530
6562
  const ChatOrderedListItemContent = 'ChatOrderedListItemContent';
6563
+ const ChatOrderedListItemPrefix = 'ChatOrderedListItemPrefix';
6531
6564
  const ChatOrderedListMarker = 'ChatOrderedListMarker';
6532
6565
  const ChatComposerAttachment = 'ChatComposerAttachment';
6533
6566
  const ChatComposerAttachmentImage = 'ChatComposerAttachmentImage';
@@ -8979,7 +9012,8 @@ const handleRemoveComposerAttachment = async (state, attachmentId) => {
8979
9012
  }
8980
9013
  return {
8981
9014
  ...state,
8982
- composerAttachments: nextComposerAttachments
9015
+ composerAttachments: nextComposerAttachments,
9016
+ composerAttachmentsHeight: getComposerAttachmentsHeight(nextComposerAttachments, state.width)
8983
9017
  };
8984
9018
  };
8985
9019
 
@@ -9423,7 +9457,23 @@ const handleClickSettings = async () => {
9423
9457
  await invoke('Main.openUri', 'app://settings.json');
9424
9458
  };
9425
9459
 
9426
- const handleContextMenuChatImageAttachment = async state => {
9460
+ const handleContextMenuChatImageAttachment = async (state, name, eventX, eventY) => {
9461
+ const getFallbackAttachment = () => {
9462
+ const attachmentsWithPreview = state.composerAttachments.filter(attachment => attachment.previewSrc);
9463
+ if (attachmentsWithPreview.length !== 1) {
9464
+ return undefined;
9465
+ }
9466
+ return attachmentsWithPreview[0];
9467
+ };
9468
+ const attachment = isComposerAttachmentPreviewInputName(name) ? state.composerAttachments.find(item => item.attachmentId === getAttachmentIdFromComposerAttachmentPreviewInputName(name)) : getFallbackAttachment();
9469
+ if (!attachment?.previewSrc) {
9470
+ return state;
9471
+ }
9472
+ await showContextMenu2(state.uid, MenuChatAttachment, eventX, eventY, {
9473
+ attachmentId: attachment.attachmentId,
9474
+ menuId: MenuChatAttachment,
9475
+ previewSrc: attachment.previewSrc
9476
+ });
9427
9477
  return state;
9428
9478
  };
9429
9479
 
@@ -10672,6 +10722,10 @@ const registerMockResponse = (state, mockResponse) => {
10672
10722
  return state;
10673
10723
  };
10674
10724
 
10725
+ const removeComposerAttachment = async (state, attachmentId) => {
10726
+ return handleRemoveComposerAttachment(state, attachmentId);
10727
+ };
10728
+
10675
10729
  const getCss = (composerHeight, composerAttachmentsHeight, modelPickerHeight, listItemHeight, chatMessageFontSize, chatMessageLineHeight, chatMessageFontFamily, chatFocusContentMaxWidth, textAreaPaddingTop, textAreaPaddingLeft, textAreaPaddingRight, textAreaPaddingBottom, chatSendAreaPaddingTop, chatSendAreaPaddingLeft, chatSendAreaPaddingRight, chatSendAreaPaddingBottom, renderHtmlCss) => {
10676
10730
  const buttonsHeight = 20;
10677
10731
  const gap = 10;
@@ -10803,6 +10857,26 @@ const getCss = (composerHeight, composerAttachmentsHeight, modelPickerHeight, li
10803
10857
  color: var(--vscode-textLink-foreground);
10804
10858
  }
10805
10859
 
10860
+ .ChatOrderedListItem{
10861
+ align-items: flex-start;
10862
+ display: flex;
10863
+ gap: 8px;
10864
+ }
10865
+
10866
+ .ChatOrderedListMarker{
10867
+ flex: none;
10868
+ min-width: 1.5em;
10869
+ }
10870
+
10871
+ .ChatOrderedListItemContent{
10872
+ flex: 1;
10873
+ min-width: 0;
10874
+ }
10875
+
10876
+ .ChatOrderedListItemPrefix{
10877
+ white-space: nowrap;
10878
+ }
10879
+
10806
10880
  .ChatToolCalls .ChatOrderedList{
10807
10881
  list-style: none;
10808
10882
  margin: 0;
@@ -11218,16 +11292,13 @@ const getComposerAttachmentClassName = displayType => {
11218
11292
  }
11219
11293
  };
11220
11294
  const getComposerAttachmentRemoveButtonDom = attachment => {
11221
- if (attachment.displayType !== 'image') {
11222
- return [];
11223
- }
11224
11295
  return [{
11225
11296
  buttonType: 'button',
11226
11297
  childCount: 1,
11227
11298
  className: ChatComposerAttachmentRemoveButton,
11228
11299
  name: getComposerAttachmentRemoveInputName(attachment.attachmentId),
11229
11300
  onClick: HandleClick,
11230
- title: removeImageAttachment(),
11301
+ title: removeAttachment(),
11231
11302
  type: Button$1
11232
11303
  }, {
11233
11304
  text: 'x',
@@ -11242,6 +11313,8 @@ const getComposerAttachmentPreviewDom = attachment => {
11242
11313
  alt: `Image preview for ${attachment.name}`,
11243
11314
  childCount: 0,
11244
11315
  className: ChatComposerAttachmentPreview,
11316
+ name: getComposerAttachmentInputName(attachment.attachmentId),
11317
+ onContextMenu: HandleContextMenuChatImageAttachment,
11245
11318
  src: attachment.previewSrc,
11246
11319
  type: Img
11247
11320
  }];
@@ -11616,24 +11689,69 @@ const getHeadingDom = (node, useChatMathWorker) => {
11616
11689
  }, ...node.children.flatMap(child => getInlineNodeDom(child, useChatMathWorker))];
11617
11690
  };
11618
11691
 
11692
+ const leadingPunctuationRegex = /^([:;,.!?]+)([\s\S]*)$/;
11693
+ const splitLeadingPunctuation = children => {
11694
+ const [firstChild, secondChild, ...restChildren] = children;
11695
+ if (firstChild?.type !== 'bold' || secondChild?.type !== 'text') {
11696
+ return {
11697
+ prefixChildren: [],
11698
+ remainingChildren: children
11699
+ };
11700
+ }
11701
+ const match = secondChild.text.match(leadingPunctuationRegex);
11702
+ if (!match) {
11703
+ return {
11704
+ prefixChildren: [],
11705
+ remainingChildren: children
11706
+ };
11707
+ }
11708
+ const [, punctuation, remainingText] = match;
11709
+ const nextChildren = restChildren;
11710
+ if (remainingText) {
11711
+ nextChildren.unshift({
11712
+ text: remainingText,
11713
+ type: 'text'
11714
+ });
11715
+ }
11716
+ return {
11717
+ prefixChildren: [firstChild, {
11718
+ text: punctuation,
11719
+ type: 'text'
11720
+ }],
11721
+ remainingChildren: nextChildren
11722
+ };
11723
+ };
11619
11724
  const getOrderedListItemDom = (item, useChatMathWorker, fallbackIndex, recurseOrdered, recurseUnordered) => {
11620
11725
  const hasNestedList = (item.nestedItems?.length || 0) > 0;
11621
11726
  const nestedListType = item.nestedListType || 'unordered-list';
11727
+ const {
11728
+ prefixChildren,
11729
+ remainingChildren
11730
+ } = splitLeadingPunctuation(item.children);
11622
11731
  const nestedListDom = hasNestedList ? [{
11623
11732
  childCount: item.nestedItems?.length || 0,
11624
11733
  className: nestedListType === 'ordered-list' ? ChatOrderedList : ChatUnorderedList,
11625
11734
  type: nestedListType === 'ordered-list' ? Ol : Ul
11626
11735
  }, ...(item.nestedItems || []).flatMap((nestedItem, index) => nestedListType === 'ordered-list' ? recurseOrdered(nestedItem, useChatMathWorker, index + 1) : recurseUnordered(nestedItem, useChatMathWorker))] : [];
11627
11736
  const marker = `${item.index ?? fallbackIndex}.`;
11737
+ const prefixDom = prefixChildren.length === 0 ? [] : [{
11738
+ childCount: prefixChildren.length,
11739
+ className: ChatOrderedListItemPrefix,
11740
+ type: Span
11741
+ }, ...prefixChildren.flatMap(child => getInlineNodeDom(child, useChatMathWorker))];
11628
11742
  return [{
11629
- childCount: item.children.length + (hasNestedList ? 1 : 0) + 1,
11743
+ childCount: 2,
11630
11744
  className: ChatOrderedListItem,
11631
11745
  type: Li
11632
11746
  }, {
11633
11747
  childCount: 1,
11634
11748
  className: ChatOrderedListMarker,
11635
11749
  type: Span
11636
- }, text(marker), ...item.children.flatMap(child => getInlineNodeDom(child, useChatMathWorker)), ...nestedListDom];
11750
+ }, text(marker), {
11751
+ childCount: (prefixDom.length === 0 ? 0 : 1) + remainingChildren.length + (hasNestedList ? 1 : 0),
11752
+ className: ChatOrderedListItemContent,
11753
+ type: Div
11754
+ }, ...prefixDom, ...remainingChildren.flatMap(child => getInlineNodeDom(child, useChatMathWorker)), ...nestedListDom];
11637
11755
  };
11638
11756
 
11639
11757
  const getTableHeadCellDom = (cell, useChatMathWorker) => {
@@ -12839,6 +12957,7 @@ const getMessagesDom = (messages, parsedMessages, openRouterApiKeyInput, openApi
12839
12957
  className: 'ChatMessages',
12840
12958
  onContextMenu: HandleMessagesContextMenu,
12841
12959
  onScroll: HandleMessagesScroll,
12960
+ role: 'log',
12842
12961
  scrollTop: messagesScrollTop,
12843
12962
  type: Div
12844
12963
  }, ...displayMessages.flatMap(item => getChatMessageDom(item.message, item.parsedContent, openRouterApiKeyInput, openApiApiKeyInput, openApiApiKeyState, openApiApiKeysSettingsUrl, openApiApiKeyInputPattern, openRouterApiKeyState, useChatMathWorker))];
@@ -14081,7 +14200,7 @@ const renderEventListeners = () => {
14081
14200
  params: ['handleModelInputBlur']
14082
14201
  }, {
14083
14202
  name: HandleContextMenuChatImageAttachment,
14084
- params: ['handleContextMenuChatImageAttachment'],
14203
+ params: ['handleContextMenuChatImageAttachment', TargetName, ClientX, ClientY],
14085
14204
  preventDefault: true
14086
14205
  }];
14087
14206
  };
@@ -14482,6 +14601,7 @@ const commandMap = {
14482
14601
  'Chat.openRunModePicker': wrapCommand(openRunModePicker),
14483
14602
  'Chat.pasteInput': wrapCommand(pasteInput),
14484
14603
  'Chat.registerMockResponse': wrapCommand(registerMockResponse),
14604
+ 'Chat.removeComposerAttachment': wrapCommand(removeComposerAttachment),
14485
14605
  'Chat.render2': render2,
14486
14606
  'Chat.renderEventListeners': renderEventListeners,
14487
14607
  'Chat.rerender': wrapCommand(rerender),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/chat-view",
3
- "version": "6.64.0",
3
+ "version": "6.65.0",
4
4
  "description": "Chat View Worker",
5
5
  "repository": {
6
6
  "type": "git",