tuikit-atomicx-vue3 4.5.0 → 4.5.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 (109) hide show
  1. package/dist/{PopoverTrigger-L8abAry7.js → PopoverPortal-DghpKKm8.js} +91 -136
  2. package/dist/PopoverTrigger-BajjNkGO.js +54 -0
  3. package/dist/{PopperContent-XdhqL8Y2.js → PopperContent-SLoFuK7k.js} +6 -6
  4. package/dist/{Teleport-CSEuZbpM.js → Teleport-DFrneqLM.js} +4 -4
  5. package/dist/baseComp/Modal/Modal.js +3 -3
  6. package/dist/components/BarrageInput/EmojiPicker/EmojiPicker.js +10 -9
  7. package/dist/components/BarrageInput/TextEditor/CharacterCountExtension.js +1 -1
  8. package/dist/components/BarrageInput/TextEditor/EditorCore.js +16 -15
  9. package/dist/components/ConversationList/ConversationPreview/ConversationPreviewAbstract.js +62 -40
  10. package/dist/components/ConversationList/ConversationPreview/ConversationPreviewTimestamp.js +29 -27
  11. package/dist/components/ConversationList/ConversationPreview/ConversationPreviewTitle.js +27 -23
  12. package/dist/components/ConversationList/ConversationPreview/ConversationPreviewTitle.vue.d.ts +1 -1
  13. package/dist/components/ConversationList/ConversationPreview/ConversationPreviewUI.js +67 -65
  14. package/dist/components/ConversationList/ConversationPreview/ConversationPreviewUnread.js +32 -30
  15. package/dist/components/ConversationList/ConversationPreview/utils.d.ts +2 -2
  16. package/dist/components/ConversationList/ConversationPreview/utils.js +81 -35
  17. package/dist/components/ConversationList/i18n/en-US.d.ts +10 -1
  18. package/dist/components/ConversationList/i18n/en-US.js +11 -2
  19. package/dist/components/ConversationList/i18n/zh-CN.d.ts +10 -1
  20. package/dist/components/ConversationList/i18n/zh-CN.js +11 -2
  21. package/dist/components/LiveScenePanel/index.js +10 -9
  22. package/dist/components/MessageInput/AttachmentPicker/index.js +10 -9
  23. package/dist/components/MessageInput/EmojiPicker/EmojiPicker.js +17 -16
  24. package/dist/components/MessageInput/QuotedMessagePreview/index.js +35 -35
  25. package/dist/components/MessageInput/TextEditor/EditorCore.d.ts +13 -12
  26. package/dist/components/MessageInput/TextEditor/EditorCore.js +54 -89
  27. package/dist/components/MessageInput/TextEditor/extensions/MentionSuggestion.js +229 -0
  28. package/dist/components/MessageInput/TextEditor/extensions/MentionSuggestion.vue.d.ts +15 -0
  29. package/dist/components/MessageInput/TextEditor/extensions/characterCountExtension.js +1 -1
  30. package/dist/components/MessageInput/TextEditor/extensions/emojiExtension.d.ts +1 -0
  31. package/dist/components/MessageInput/TextEditor/extensions/emojiExtension.js +22 -0
  32. package/dist/components/MessageInput/TextEditor/extensions/enterKeyExtension.d.ts +3 -0
  33. package/dist/components/MessageInput/TextEditor/extensions/enterKeyExtension.js +15 -0
  34. package/dist/components/MessageInput/TextEditor/extensions/imageExtension.js +2 -2
  35. package/dist/components/MessageInput/TextEditor/extensions/index.d.ts +8 -0
  36. package/dist/components/MessageInput/TextEditor/extensions/index.js +12 -0
  37. package/dist/components/MessageInput/TextEditor/extensions/mentionExtension.d.ts +5 -0
  38. package/dist/components/MessageInput/TextEditor/extensions/mentionExtension.js +330 -0
  39. package/dist/components/MessageInput/TextEditor/index.js +62 -62
  40. package/dist/components/MessageInput/i18n/en-US.d.ts +3 -0
  41. package/dist/components/MessageInput/i18n/en-US.js +4 -1
  42. package/dist/components/MessageInput/i18n/index.d.ts +6 -0
  43. package/dist/components/MessageInput/i18n/zh-CN.d.ts +3 -0
  44. package/dist/components/MessageInput/i18n/zh-CN.js +4 -1
  45. package/dist/components/MessageList/Message/ImageMessage/ImageMessage.js +119 -89
  46. package/dist/components/MessageList/Message/ImageMessage/ImagePreview.js +142 -0
  47. package/dist/components/MessageList/Message/ImageMessage/ImagePreview.vue.d.ts +20 -0
  48. package/dist/components/MessageList/Message/Message.vue.d.ts +8 -0
  49. package/dist/components/MessageList/Message/MessageLayout/MessageActionDropdown/MessageActionDropdown.js +3 -3
  50. package/dist/components/MessageList/Message/MessageLayout/MessageLayout.js +69 -58
  51. package/dist/components/MessageList/Message/MessageLayout/MessageLayout.vue.d.ts +8 -0
  52. package/dist/components/MessageList/Message/index.js +8 -4
  53. package/dist/components/MessageList/MessageList.js +98 -90
  54. package/dist/components/MessageList/MessageList.vue.d.ts +1 -1
  55. package/dist/components/MessageList/index.d.ts +21 -3
  56. package/dist/components/Search/SearchResults/SearchResultsItem/Message/Message.js +6 -6
  57. package/dist/components/Search/SearchResults/SearchResultsItem/Message/Message.vue.d.ts +1 -1
  58. package/dist/index-BvFYOUyz.js +2936 -0
  59. package/dist/{index-Do-2CngU.js → index-C8Jw_xE4.js} +1621 -1731
  60. package/dist/{index-7vNB_Vx8.js → index-CiYL_XsE.js} +1 -1
  61. package/dist/index-CzCDLp99.js +2174 -0
  62. package/dist/index.d.ts +1 -1
  63. package/dist/index.js +103 -103
  64. package/dist/states/MessageActionState/MessageActionState.js +83 -223
  65. package/dist/states/MessageInputState/MessageInputState.js +115 -83
  66. package/dist/states/MessageInputState/type.d.ts +36 -10
  67. package/dist/states/MessageInputState/utils.d.ts +1 -5
  68. package/dist/states/MessageListState/MessageListState.d.ts +1 -1
  69. package/dist/styles/index.css +1 -1
  70. package/dist/{chat/index.d.ts → subEntry/chat/chat.d.ts} +2112 -2087
  71. package/dist/subEntry/chat/chat.js +89 -0
  72. package/dist/subEntry/chat/index.d.ts +11 -0
  73. package/dist/subEntry/chat/index.js +81 -0
  74. package/dist/{chat → subEntry/chat}/server.js +4 -4
  75. package/dist/{useId-CtirfF0W.js → useId-D5WE76CM.js} +1 -1
  76. package/dist/{utils-DaB7eSu5.js → utils-CttDpxqz.js} +1 -1
  77. package/package.json +8 -6
  78. package/src/components/ConversationList/ConversationPreview/ConversationPreview.scss +8 -0
  79. package/src/components/ConversationList/ConversationPreview/ConversationPreviewAbstract.vue +32 -1
  80. package/src/components/ConversationList/ConversationPreview/ConversationPreviewTitle.vue +3 -2
  81. package/src/components/ConversationList/ConversationPreview/utils.ts +98 -28
  82. package/src/components/ConversationList/i18n/en-US.ts +10 -1
  83. package/src/components/ConversationList/i18n/zh-CN.ts +10 -1
  84. package/src/components/LiveScenePanel/index.vue +1 -0
  85. package/src/components/MessageInput/QuotedMessagePreview/QuotedMessagePreview.vue +19 -22
  86. package/src/components/MessageInput/TextEditor/Editor.scss +25 -0
  87. package/src/components/MessageInput/TextEditor/EditorCore.ts +79 -99
  88. package/src/components/MessageInput/TextEditor/TextEditor.vue +64 -68
  89. package/src/components/MessageInput/TextEditor/extensions/MentionSuggestion.vue +449 -0
  90. package/src/components/MessageInput/TextEditor/extensions/emojiExtension.ts +22 -0
  91. package/src/components/MessageInput/TextEditor/extensions/enterKeyExtension.ts +22 -0
  92. package/src/components/MessageInput/TextEditor/extensions/index.ts +8 -0
  93. package/src/components/MessageInput/TextEditor/extensions/mentionExtension.ts +87 -0
  94. package/src/components/MessageInput/i18n/en-US.ts +3 -0
  95. package/src/components/MessageInput/i18n/zh-CN.ts +3 -0
  96. package/src/components/MessageList/Message/ImageMessage/ImageMessage.vue +49 -0
  97. package/src/components/MessageList/Message/ImageMessage/ImagePreview.vue +344 -0
  98. package/src/components/MessageList/Message/Message.vue +6 -0
  99. package/src/components/MessageList/Message/MessageLayout/MessageLayout.vue +8 -1
  100. package/src/components/MessageList/MessageList.vue +36 -14
  101. package/src/components/Search/SearchResults/SearchResultsItem/Message/Message.vue +30 -31
  102. package/src/index.ts +1 -1
  103. package/src/{chat/index.ts → subEntry/chat/chat.ts} +25 -18
  104. package/src/subEntry/chat/index.ts +13 -0
  105. package/src/{chat → subEntry/chat}/server.ts +3 -3
  106. package/dist/chat/index.js +0 -59
  107. package/dist/index-ZILx4LYk.js +0 -4826
  108. package/dist/states/SearchState.d.ts +0 -314
  109. /package/dist/{chat → subEntry/chat}/server.d.ts +0 -0
@@ -1,48 +1,72 @@
1
- import Image from '@tiptap/extension-image';
1
+ /**
2
+ * EditorCore - Pure functional utilities for Tiptap editor
3
+ * Provides extension configuration and content conversion
4
+ */
2
5
  import Placeholder from '@tiptap/extension-placeholder';
3
6
  import StarterKit from '@tiptap/starter-kit';
4
- import { Extension, Editor } from '@tiptap/vue-3';
5
7
  import { MessageContentType } from '../../../states/MessageInputState';
6
- import { CharacterCount } from './extensions/characterCountExtension';
7
- import { createImageExtension } from './extensions/imageExtension';
8
+ import {
9
+ CharacterCount,
10
+ createEmojiExtension,
11
+ createEnterKeyExtension,
12
+ createImageExtension,
13
+ createMentionExtension,
14
+ } from './extensions';
8
15
  import type { InputContent } from '../../../states/MessageInputState';
9
- import type { JSONContent, EditorOptions as TiptapEditorOptions } from '@tiptap/vue-3';
16
+ import type { JSONContent, Extensions } from '@tiptap/vue-3';
10
17
  import './Editor.scss';
11
18
 
12
- function createEmojiExtension() {
13
- return Image.extend({
14
- name: MessageContentType.EMOJI,
15
- inline: true,
16
- group: 'inline',
17
- draggable: true,
18
- addOptions() {
19
- return {
20
- ...this.parent?.(),
21
- HTMLAttributes: {
22
- class: 'message-emoji',
23
- },
24
- };
25
- },
26
- });
19
+ // ============================================================================
20
+ // Extension Configuration
21
+ // ============================================================================
22
+
23
+ interface ExtensionOptions {
24
+ placeholder?: string;
25
+ maxLength?: number;
26
+ showPlaceholderOnlyWhenEditable?: boolean;
27
+ onEnter?: () => void;
27
28
  }
28
29
 
29
- function createEnterKeyExtension(options?: { onEnter?: (() => void) | undefined }) {
30
- return Extension.create({
31
- addKeyboardShortcuts() {
32
- return {
33
- 'Enter': () => {
34
- options?.onEnter?.();
35
- return true;
36
- },
37
- 'Mod-Enter': ({ editor }) => {
38
- editor.commands.setHardBreak();
39
- return true;
40
- },
41
- };
42
- },
43
- });
30
+ /**
31
+ * Create all editor extensions with given options
32
+ */
33
+ function createExtensions(options: ExtensionOptions = {}): Extensions {
34
+ const {
35
+ placeholder = '',
36
+ maxLength,
37
+ showPlaceholderOnlyWhenEditable = true,
38
+ onEnter,
39
+ } = options;
40
+
41
+ return [
42
+ StarterKit.configure({
43
+ bold: false,
44
+ italic: false,
45
+ strike: false,
46
+ code: false,
47
+ }),
48
+ CharacterCount.configure({
49
+ limit: maxLength,
50
+ }),
51
+ createEnterKeyExtension(onEnter),
52
+ createEmojiExtension(),
53
+ createImageExtension(),
54
+ createMentionExtension(),
55
+ Placeholder.configure({
56
+ placeholder,
57
+ showOnlyWhenEditable: showPlaceholderOnlyWhenEditable,
58
+ }),
59
+ ];
44
60
  }
45
61
 
62
+ // ============================================================================
63
+ // Content Conversion
64
+ // ============================================================================
65
+
66
+ /**
67
+ * Convert Tiptap JSON content to business InputContent array
68
+ * Uses simple switch-case for clarity (no over-engineered registry pattern)
69
+ */
46
70
  function convertEditorContent(node: JSONContent): InputContent[] {
47
71
  if (!node?.content) {
48
72
  return [];
@@ -57,11 +81,13 @@ function convertEditorContent(node: JSONContent): InputContent[] {
57
81
  content: child.text,
58
82
  }]
59
83
  : [];
84
+
60
85
  case 'image':
61
86
  return [{
62
87
  type: MessageContentType.IMAGE,
63
88
  content: child.attrs?.fileData,
64
89
  }];
90
+
65
91
  case 'emoji':
66
92
  return [{
67
93
  type: MessageContentType.EMOJI,
@@ -71,81 +97,35 @@ function convertEditorContent(node: JSONContent): InputContent[] {
71
97
  text: child.attrs?.title,
72
98
  },
73
99
  }];
100
+
74
101
  case 'hardBreak':
75
102
  return [{
76
103
  type: MessageContentType.TEXT,
77
104
  content: '\n',
78
105
  }];
106
+
107
+ case 'mention':
108
+ return [{
109
+ type: MessageContentType.MENTION,
110
+ content: {
111
+ id: child.attrs?.id,
112
+ label: child.attrs?.label,
113
+ mentionSuggestionChar: child.attrs?.mentionSuggestionChar,
114
+ },
115
+ }];
116
+
79
117
  default:
118
+ // Recursively handle nested content (e.g., paragraph nodes)
80
119
  return convertEditorContent(child);
81
120
  }
82
121
  });
83
122
  }
84
123
 
85
- interface EditorOptions {
86
- element: Element;
87
- placeholder?: string;
88
- autoFocus?: boolean;
89
- disabled?: boolean;
90
- maxLength?: number;
91
- isPlaceholderOnlyShowWhenEditable?: boolean;
92
- onUpdate?: (content: InputContent[]) => void;
93
- onEnter?: () => void;
94
- onFocus?: () => void;
95
- onBlur?: () => void;
96
- }
97
-
98
- function createEditor({
99
- element,
100
- placeholder = '',
101
- autoFocus = false,
102
- disabled = false,
103
- isPlaceholderOnlyShowWhenEditable = true,
104
- maxLength = undefined,
105
- onUpdate,
106
- onEnter,
107
- onFocus,
108
- onBlur,
109
- }: EditorOptions) {
110
- const createBaseExtensions = (enterHandler?: () => void) => [
111
- StarterKit.configure({
112
- bold: false,
113
- italic: false,
114
- strike: false,
115
- code: false,
116
- }),
117
- CharacterCount.configure({
118
- limit: maxLength,
119
- }),
120
- createEnterKeyExtension(enterHandler ? { onEnter: enterHandler } : undefined),
121
- createEmojiExtension(),
122
- createImageExtension(),
123
- Placeholder.configure({
124
- placeholder,
125
- showOnlyWhenEditable: isPlaceholderOnlyShowWhenEditable,
126
- }),
127
- ];
128
-
129
- const editorConfig: Partial<TiptapEditorOptions> = {
130
- element,
131
- autofocus: autoFocus,
132
- editable: !disabled,
133
- extensions: createBaseExtensions(onEnter),
134
- onUpdate: ({ editor }) => {
135
- const content = convertEditorContent(editor.getJSON());
136
- onUpdate?.(content);
137
- },
138
- onFocus,
139
- onBlur,
140
- };
141
-
142
- return new Editor(editorConfig);
143
- }
124
+ // ============================================================================
125
+ // Exports
126
+ // ============================================================================
144
127
 
145
128
  export {
146
- createEditor,
147
- };
148
-
149
- export type {
150
- Editor,
129
+ createExtensions,
130
+ convertEditorContent,
151
131
  };
@@ -3,10 +3,10 @@
3
3
  <div :class="styles['input-prefix']">
4
4
  <slot name="inputPrefix" />
5
5
  </div>
6
- <div
7
- ref="editorDomRef"
8
- :key="props.disabled ? 'disabled' : 'enabled'"
6
+ <EditorContent
7
+ :editor="editor"
9
8
  :class="styles['editor']"
9
+ class="message-input"
10
10
  />
11
11
  <div :class="styles['input-suffix']">
12
12
  <slot name="inputSuffix" />
@@ -15,13 +15,13 @@
15
15
  </template>
16
16
 
17
17
  <script setup lang="ts">
18
- import { ref, onMounted, onUnmounted, computed, watch } from 'vue';
18
+ import { computed, watch, onBeforeUnmount } from 'vue';
19
19
  import { useUIKit } from '@tencentcloud/uikit-base-component-vue3';
20
+ import { useEditor, EditorContent } from '@tiptap/vue-3';
20
21
  import { useConversationListState } from '../../../states/ConversationListState';
21
22
  import { useMessageInputState } from '../../../states/MessageInputState';
22
- import { createEditor } from './EditorCore';
23
+ import { createExtensions, convertEditorContent } from './EditorCore';
23
24
  import styles from './TextEditor.module.scss';
24
- import type { Editor } from './EditorCore';
25
25
 
26
26
  interface TextEditorProps {
27
27
  autoFocus?: boolean;
@@ -41,85 +41,81 @@ const { t, language } = useUIKit();
41
41
  const { activeConversation } = useConversationListState();
42
42
  const { updateRawValue, sendMessage, setEditorInstance, setContent } = useMessageInputState();
43
43
 
44
- const editorDomRef = ref<HTMLDivElement | null>(null);
45
- const isFocused = ref(props.autoFocus);
46
-
47
44
  const computedPlaceholder = computed(() => props.placeholder ?? t('MessageInput.enter_a_message'));
48
45
 
49
- let editorInstance: Editor | null = null;
46
+ // Handle Enter key to send message
47
+ const handleEnter = () => {
48
+ sendMessage();
49
+ setContent('');
50
+ };
50
51
 
51
- onMounted(() => {
52
- const element = editorDomRef.value;
53
- if (!element) {
54
- return;
52
+ // Create editor using Tiptap's official useEditor composable
53
+ const editor = useEditor({
54
+ autofocus: props.autoFocus,
55
+ editable: !props.disabled,
56
+ extensions: createExtensions({
57
+ placeholder: computedPlaceholder.value,
58
+ maxLength: props.maxLength,
59
+ showPlaceholderOnlyWhenEditable: props.placeholder === undefined,
60
+ onEnter: handleEnter,
61
+ }),
62
+ onUpdate: ({ editor: editorInstance }) => {
63
+ const content = convertEditorContent(editorInstance.getJSON());
64
+ updateRawValue(content);
65
+ },
66
+ });
67
+
68
+ // Sync editor instance to global state
69
+ watch(editor, (newEditor) => {
70
+ setEditorInstance(newEditor ?? null);
71
+ }, { immediate: true });
72
+
73
+ // Reactive: disabled prop
74
+ watch(() => props.disabled, (newDisabled) => {
75
+ editor.value?.setEditable(!newDisabled);
76
+ if (newDisabled) {
77
+ setContent('');
55
78
  }
79
+ });
56
80
 
57
- element.classList.add('message-input');
81
+ // Reactive: placeholder (including language change)
82
+ watch([computedPlaceholder, language], () => {
83
+ if (!editor.value) {
84
+ return;
85
+ }
58
86
 
59
- if (!element.dataset.editorCreated) {
60
- editorInstance = createEditor({
61
- element,
62
- placeholder: computedPlaceholder.value,
63
- isPlaceholderOnlyShowWhenEditable: props.placeholder === undefined,
64
- autoFocus: props.autoFocus,
65
- disabled: props.disabled,
66
- maxLength: props.maxLength,
67
- onUpdate: (content) => {
68
- updateRawValue(content);
69
- },
70
- onEnter: () => {
71
- sendMessage();
72
- setContent('');
73
- },
74
- onFocus: () => {
75
- isFocused.value = true;
76
- },
77
- onBlur: () => {
78
- isFocused.value = false;
79
- },
80
- });
81
- element.dataset.editorCreated = 'true';
82
- setEditorInstance(editorInstance);
87
+ const placeholderExtension = editor.value.extensionManager.extensions.find(
88
+ ext => ext.name === 'placeholder',
89
+ );
90
+ if (placeholderExtension) {
91
+ placeholderExtension.options.placeholder = computedPlaceholder.value;
92
+ editor.value.view.updateState(editor.value.state);
83
93
  }
84
94
  });
85
95
 
86
- onUnmounted(() => {
87
- const element = editorDomRef.value;
88
- if (editorInstance && element) {
89
- editorInstance.destroy();
90
- element.removeAttribute('data-editor-created');
91
- setEditorInstance(null);
96
+ // Reactive: maxLength
97
+ watch(() => props.maxLength, (newMaxLength) => {
98
+ if (!editor.value) {
99
+ return;
100
+ }
101
+
102
+ const characterCountExtension = editor.value.extensionManager.extensions.find(
103
+ ext => ext.name === 'characterCount',
104
+ );
105
+ if (characterCountExtension) {
106
+ characterCountExtension.options.limit = newMaxLength;
92
107
  }
93
108
  });
94
109
 
110
+ // Clear content when conversation changes
95
111
  watch(activeConversation, (newConversation, oldConversation) => {
96
112
  if (newConversation?.conversationID !== oldConversation?.conversationID) {
97
113
  setContent('');
98
114
  }
99
115
  });
100
116
 
101
- // Watch language change and update placeholder using Tiptap's extensionManager
102
- watch(language, () => {
103
- if (editorInstance && props.placeholder === undefined) {
104
- // Update placeholder extension options
105
- const placeholderExtension = editorInstance.extensionManager.extensions.find(
106
- ext => ext.name === 'placeholder',
107
- );
108
- if (placeholderExtension) {
109
- // eslint-disable-next-line no-param-reassign
110
- placeholderExtension.options.placeholder = computedPlaceholder.value;
111
- // Force re-render to apply new placeholder
112
- editorInstance.view.updateState(editorInstance.state);
113
- }
114
- }
115
- });
116
-
117
- watch(() => props.disabled, (newDisabled) => {
118
- if (editorInstance) {
119
- editorInstance.setEditable(!newDisabled);
120
- if (newDisabled) {
121
- setContent('');
122
- }
123
- }
117
+ // Cleanup on unmount
118
+ onBeforeUnmount(() => {
119
+ setEditorInstance(null);
124
120
  });
125
121
  </script>