@homecode/ui 5.1.17 → 5.3.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.
- package/dist/esm/index.js +5 -0
- package/dist/esm/src/components/Autocomplete/Autocomplete.js +5 -0
- package/dist/esm/src/components/InputFile/InputFile.js +5 -0
- package/dist/esm/src/components/PromptComposer/PromptComposer.helpers.js +44 -0
- package/dist/esm/src/components/PromptComposer/PromptComposer.js +35 -0
- package/dist/esm/src/components/PromptComposer/PromptComposer.styl.js +7 -0
- package/dist/esm/src/components/PromptComposer/promptComposerDoc.js +17 -0
- package/dist/esm/src/components/PromptComposer/promptComposerInsert.js +101 -0
- package/dist/esm/src/components/PromptComposer/usePromptComposerEditor.js +192 -0
- package/dist/esm/src/components/Slider/Slider.styl.js +1 -1
- package/dist/esm/src/tiptap/slash-mention/SlashSuggestionList.js +57 -0
- package/dist/esm/src/tiptap/slash-mention/SlashSuggestionList.styl.js +7 -0
- package/dist/esm/src/tiptap/slash-mention/createSlashMentionExtension.js +202 -0
- package/dist/esm/src/tiptap/slash-mention/defaultChatSlashItems.js +12 -0
- package/dist/esm/types/node_modules/@tiptap/pm/state/index.d.ts +1 -0
- package/dist/esm/types/src/components/PromptComposer/PromptComposer.d.ts +13 -0
- package/dist/esm/types/src/components/PromptComposer/PromptComposer.helpers.d.ts +8 -0
- package/dist/esm/types/src/components/PromptComposer/PromptComposer.types.d.ts +19 -0
- package/dist/esm/types/src/components/PromptComposer/index.d.ts +7 -0
- package/dist/esm/types/src/components/PromptComposer/promptComposerDoc.d.ts +3 -0
- package/dist/esm/types/src/components/PromptComposer/promptComposerInsert.d.ts +42 -0
- package/dist/esm/types/src/components/PromptComposer/usePromptComposerEditor.d.ts +19 -0
- package/dist/esm/types/src/components/index.d.ts +1 -0
- package/dist/esm/types/src/index.d.ts +1 -0
- package/dist/esm/types/src/tiptap/slash-mention/SlashSuggestionList.d.ts +11 -0
- package/dist/esm/types/src/tiptap/slash-mention/createSlashMentionExtension.d.ts +21 -0
- package/dist/esm/types/src/tiptap/slash-mention/defaultChatSlashItems.d.ts +4 -0
- package/dist/esm/types/src/tiptap/slash-mention/index.d.ts +5 -0
- package/dist/esm/types/src/tiptap/slash-mention/types.d.ts +28 -0
- package/package.json +8 -1
- package/.cursor/debug-8c6f78.log +0 -44
- package/.cursor/debug-a8590a.log +0 -26
- package/.cursor/debug-cdef6d.log +0 -694
- package/.cursor/debug-e1fd63.log +0 -83
- package/.cursor/debug.log +0 -207
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { mergeAttributes } from '@tiptap/core';
|
|
2
|
+
import Mention from '@tiptap/extension-mention';
|
|
3
|
+
import { ReactRenderer } from '@tiptap/react';
|
|
4
|
+
import { SlashSuggestionList } from './SlashSuggestionList.js';
|
|
5
|
+
import S from './SlashSuggestionList.styl.js';
|
|
6
|
+
import { filterSlashItems } from './defaultChatSlashItems.js';
|
|
7
|
+
|
|
8
|
+
const SlashMention = Mention.extend({
|
|
9
|
+
addAttributes() {
|
|
10
|
+
return {
|
|
11
|
+
...this.parent?.(),
|
|
12
|
+
className: {
|
|
13
|
+
default: null,
|
|
14
|
+
parseHTML: element => element.getAttribute('data-slash-class'),
|
|
15
|
+
renderHTML: attributes => {
|
|
16
|
+
if (!attributes.className)
|
|
17
|
+
return {};
|
|
18
|
+
return { 'data-slash-class': attributes.className };
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
color: {
|
|
22
|
+
default: null,
|
|
23
|
+
parseHTML: element => element.getAttribute('data-slash-color'),
|
|
24
|
+
renderHTML: attributes => {
|
|
25
|
+
if (!attributes.color)
|
|
26
|
+
return {};
|
|
27
|
+
return { 'data-slash-color': attributes.color };
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
const SUGGESTION_GAP_PX = 4;
|
|
34
|
+
function placeSlashSuggestionPopup(popupElement, clientRect, placement) {
|
|
35
|
+
if (!clientRect)
|
|
36
|
+
return;
|
|
37
|
+
const el = popupElement;
|
|
38
|
+
const popupHeight = el.getBoundingClientRect().height;
|
|
39
|
+
const spaceBelow = window.innerHeight - clientRect.bottom - SUGGESTION_GAP_PX;
|
|
40
|
+
const spaceAbove = clientRect.top - SUGGESTION_GAP_PX;
|
|
41
|
+
let showAbove = placement === 'above';
|
|
42
|
+
if (placement === 'auto') {
|
|
43
|
+
showAbove = spaceBelow < popupHeight && spaceAbove >= spaceBelow;
|
|
44
|
+
}
|
|
45
|
+
const top = showAbove
|
|
46
|
+
? Math.max(SUGGESTION_GAP_PX, clientRect.top - popupHeight - SUGGESTION_GAP_PX)
|
|
47
|
+
: clientRect.bottom + SUGGESTION_GAP_PX;
|
|
48
|
+
el.style.left = `${clientRect.left}px`;
|
|
49
|
+
el.style.top = `${top}px`;
|
|
50
|
+
}
|
|
51
|
+
function slashMentionSuggestionRender(uiRef, placement = 'below') {
|
|
52
|
+
let popup = null;
|
|
53
|
+
const place = (props) => {
|
|
54
|
+
if (!popup?.element)
|
|
55
|
+
return;
|
|
56
|
+
placeSlashSuggestionPopup(popup.element, props.clientRect?.() ?? null, placement);
|
|
57
|
+
};
|
|
58
|
+
return {
|
|
59
|
+
onStart: props => {
|
|
60
|
+
uiRef.current = null;
|
|
61
|
+
popup?.destroy?.();
|
|
62
|
+
popup = new ReactRenderer(SlashSuggestionList, {
|
|
63
|
+
editor: props.editor,
|
|
64
|
+
props: {
|
|
65
|
+
items: props.items,
|
|
66
|
+
command: props.command,
|
|
67
|
+
listHandleRef: uiRef,
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
popup.element.style.position = 'fixed';
|
|
71
|
+
popup.element.style.margin = '0';
|
|
72
|
+
popup.element.style.zIndex = '10002';
|
|
73
|
+
document.body.append(popup.element);
|
|
74
|
+
place(props);
|
|
75
|
+
requestAnimationFrame(() => place(props));
|
|
76
|
+
},
|
|
77
|
+
onUpdate: props => {
|
|
78
|
+
if (!popup)
|
|
79
|
+
return;
|
|
80
|
+
popup.updateProps({
|
|
81
|
+
items: props.items,
|
|
82
|
+
command: props.command,
|
|
83
|
+
listHandleRef: uiRef,
|
|
84
|
+
});
|
|
85
|
+
place(props);
|
|
86
|
+
requestAnimationFrame(() => place(props));
|
|
87
|
+
},
|
|
88
|
+
onExit: () => {
|
|
89
|
+
popup?.destroy();
|
|
90
|
+
popup?.element?.remove?.();
|
|
91
|
+
popup = null;
|
|
92
|
+
uiRef.current = null;
|
|
93
|
+
},
|
|
94
|
+
onKeyDown: ({ event }) => uiRef.current?.onKeyboardEvent(event) ?? false,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function slashMentionChipStyle(color) {
|
|
98
|
+
if (!color)
|
|
99
|
+
return undefined;
|
|
100
|
+
return `color: ${color}; background-color: color-mix(in srgb, ${color} 30%, transparent);`;
|
|
101
|
+
}
|
|
102
|
+
function insertDefaultMention(editor, range, item, slashChar) {
|
|
103
|
+
const nodeAfter = editor.view.state.selection.$to.nodeAfter;
|
|
104
|
+
const extend = nodeAfter?.text?.startsWith(' ') ? 1 : 0;
|
|
105
|
+
const adjusted = extend ? { ...range, to: range.to + extend } : range;
|
|
106
|
+
editor
|
|
107
|
+
.chain()
|
|
108
|
+
.focus()
|
|
109
|
+
.insertContentAt(adjusted, [
|
|
110
|
+
{
|
|
111
|
+
type: 'mention',
|
|
112
|
+
attrs: {
|
|
113
|
+
id: item.id,
|
|
114
|
+
label: item.label,
|
|
115
|
+
mentionSuggestionChar: slashChar,
|
|
116
|
+
className: item.className ?? null,
|
|
117
|
+
color: item.color ?? null,
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
{ type: 'text', text: ' ' },
|
|
121
|
+
])
|
|
122
|
+
.run();
|
|
123
|
+
queueMicrotask(() => {
|
|
124
|
+
editor.view.dom.ownerDocument?.defaultView
|
|
125
|
+
?.getSelection?.()
|
|
126
|
+
?.collapseToEnd();
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
function allowSlashTrigger({ state, range, }) {
|
|
130
|
+
const type = state.schema.nodes['mention'];
|
|
131
|
+
const $from = state.doc.resolve(range.from);
|
|
132
|
+
if (!type || !$from.parent.type.contentMatch.matchType(type))
|
|
133
|
+
return false;
|
|
134
|
+
if ($from.parentOffset === 0)
|
|
135
|
+
return true;
|
|
136
|
+
const before = state.doc.textBetween(range.from - 1, range.from);
|
|
137
|
+
return /\s/.test(before);
|
|
138
|
+
}
|
|
139
|
+
function createSlashMentionExtension({ items: resolvedItems, slashChar = '/', pluginKey, onItemCommand, suggestionPlacement = 'below', onSuggestionUiActiveChange, }) {
|
|
140
|
+
const uiRef = {
|
|
141
|
+
current: null,
|
|
142
|
+
};
|
|
143
|
+
return SlashMention.configure({
|
|
144
|
+
renderText({ node }) {
|
|
145
|
+
return `/${node.attrs.id}`;
|
|
146
|
+
},
|
|
147
|
+
renderHTML({ options, node }) {
|
|
148
|
+
const id = typeof node.attrs.id === 'string'
|
|
149
|
+
? node.attrs.id
|
|
150
|
+
: String(node.attrs.id ?? '');
|
|
151
|
+
const label = typeof node.attrs.label === 'string' && node.attrs.label.trim() !== ''
|
|
152
|
+
? node.attrs.label
|
|
153
|
+
: id;
|
|
154
|
+
const color = typeof node.attrs.color === 'string' ? node.attrs.color : null;
|
|
155
|
+
const className = [S.mention, node.attrs.className]
|
|
156
|
+
.filter(Boolean)
|
|
157
|
+
.join(' ');
|
|
158
|
+
const chipStyle = slashMentionChipStyle(color);
|
|
159
|
+
return [
|
|
160
|
+
'span',
|
|
161
|
+
mergeAttributes({
|
|
162
|
+
'data-type': 'mention',
|
|
163
|
+
'data-slash-command': id,
|
|
164
|
+
class: className,
|
|
165
|
+
...(chipStyle ? { style: chipStyle } : {}),
|
|
166
|
+
}, options.HTMLAttributes),
|
|
167
|
+
label,
|
|
168
|
+
];
|
|
169
|
+
},
|
|
170
|
+
suggestion: {
|
|
171
|
+
char: slashChar,
|
|
172
|
+
pluginKey,
|
|
173
|
+
allowedPrefixes: [' ', '\n', '\t', '\r'],
|
|
174
|
+
allow: props => allowSlashTrigger(props),
|
|
175
|
+
items: ({ query }) => Promise.resolve(filterSlashItems(resolvedItems, query)),
|
|
176
|
+
command: ({ editor, range, props }) => {
|
|
177
|
+
const item = props;
|
|
178
|
+
if (onItemCommand?.({ editor, range, item }) === true) {
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
insertDefaultMention(editor, range, item, slashChar);
|
|
182
|
+
return null;
|
|
183
|
+
},
|
|
184
|
+
render: () => {
|
|
185
|
+
const menu = slashMentionSuggestionRender(uiRef, suggestionPlacement);
|
|
186
|
+
return {
|
|
187
|
+
...menu,
|
|
188
|
+
onStart: props => {
|
|
189
|
+
onSuggestionUiActiveChange?.(true);
|
|
190
|
+
menu.onStart?.(props);
|
|
191
|
+
},
|
|
192
|
+
onExit: props => {
|
|
193
|
+
menu.onExit?.(props);
|
|
194
|
+
onSuggestionUiActiveChange?.(false);
|
|
195
|
+
},
|
|
196
|
+
};
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export { createSlashMentionExtension, slashMentionSuggestionRender };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Empty default; app passes slashCommandItems to enable menu. */
|
|
2
|
+
const DEFAULT_CHAT_SLASH_ITEMS = [];
|
|
3
|
+
function filterSlashItems(items, query) {
|
|
4
|
+
const q = query.trim().toLowerCase();
|
|
5
|
+
if (!q)
|
|
6
|
+
return items;
|
|
7
|
+
return items.filter(item => item.id.toLowerCase().includes(q) ||
|
|
8
|
+
item.label.toLowerCase().includes(q) ||
|
|
9
|
+
(item.description?.toLowerCase().includes(q) ?? false));
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export { DEFAULT_CHAT_SLASH_ITEMS, filterSlashItems };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from 'prosemirror-state';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type PromptComposerHandle } from './promptComposerInsert';
|
|
2
|
+
export type { PromptComposerHandle, PromptComposerInsertOptions, } from './promptComposerInsert';
|
|
3
|
+
export declare const PromptComposer: import("react").ForwardRefExoticComponent<import("react").HTMLAttributes<HTMLDivElement> & {
|
|
4
|
+
disabled?: boolean;
|
|
5
|
+
placeholder?: string;
|
|
6
|
+
slashCommandItems?: import(".").SlashCommandItem[];
|
|
7
|
+
onSlashItemCommand?: import(".").SlashOnItemCommand;
|
|
8
|
+
prefillMessage?: string;
|
|
9
|
+
attachmentsCount?: number;
|
|
10
|
+
allowEnterSubmit?: boolean;
|
|
11
|
+
onSubmit?: (text: string, editor: import("@tiptap/core").Editor) => void;
|
|
12
|
+
onChange?: (text: string, editor: import("@tiptap/core").Editor) => void;
|
|
13
|
+
} & import("react").RefAttributes<PromptComposerHandle>>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Keep in sync with `PromptComposer.styl` max/min heights. */
|
|
2
|
+
export declare const PROMPT_COMPOSER_MAX_HEIGHT_PX = 200;
|
|
3
|
+
export declare const PROMPT_COMPOSER_MIN_HEIGHT_PX = 40;
|
|
4
|
+
export declare function promptComposerSafeEditorDom(editor: {
|
|
5
|
+
readonly isDestroyed?: boolean;
|
|
6
|
+
} | null | undefined): HTMLElement | null;
|
|
7
|
+
/** Autosize `.ProseMirror` root: empty -> floor, text -> measured height with clamp. */
|
|
8
|
+
export declare function syncPromptComposerHeight(el: HTMLElement, text: string): void;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Editor } from '@tiptap/core';
|
|
2
|
+
import type { HTMLAttributes } from 'react';
|
|
3
|
+
import type { SlashCommandItem, SlashOnItemCommand } from '../../tiptap/slash-mention';
|
|
4
|
+
export type Props = HTMLAttributes<HTMLDivElement> & {
|
|
5
|
+
disabled?: boolean;
|
|
6
|
+
placeholder?: string;
|
|
7
|
+
slashCommandItems?: SlashCommandItem[];
|
|
8
|
+
onSlashItemCommand?: SlashOnItemCommand;
|
|
9
|
+
prefillMessage?: string | null;
|
|
10
|
+
/** Staged attachment count - Enter can submit even when text empty. */
|
|
11
|
+
attachmentsCount?: number;
|
|
12
|
+
/** Mobile usually sets false so Enter inserts newline. */
|
|
13
|
+
allowEnterSubmit?: boolean;
|
|
14
|
+
/** Called when user presses Enter to submit. */
|
|
15
|
+
onSubmit?: (text: string, editor: Editor) => void;
|
|
16
|
+
/** Called on every transaction with plain text value. */
|
|
17
|
+
onChange?: (text: string, editor: Editor) => void;
|
|
18
|
+
};
|
|
19
|
+
export type PromptComposerProps = Props;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { PromptComposer } from './PromptComposer';
|
|
2
|
+
export type { PromptComposerProps } from './PromptComposer.types';
|
|
3
|
+
export { usePromptComposerEditor } from './usePromptComposerEditor';
|
|
4
|
+
export type { UsePromptComposerEditorOptions } from './usePromptComposerEditor';
|
|
5
|
+
export { getPromptComposerTokenRangeBeforePos, createPromptComposerHandle, insertPromptComposerContentAtCaret, promptComposerChipHtml, promptComposerMentionNode, PROMPT_COMPOSER_COMMAND_CHIP_CLASS, } from './promptComposerInsert';
|
|
6
|
+
export type { PromptComposerHandle, PromptComposerInsertOptions, PromptComposerMentionNodeInput, } from './promptComposerInsert';
|
|
7
|
+
export type { SlashCommandItem, SlashItemCommandContext, SlashOnItemCommand, SlashSuggestionPlacement, } from '../../tiptap/slash-mention';
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Editor, JSONContent } from '@tiptap/core';
|
|
2
|
+
export type PromptComposerInsertOptions = {
|
|
3
|
+
/** Explicit document range to replace before insert. */
|
|
4
|
+
replaceRange?: {
|
|
5
|
+
from: number;
|
|
6
|
+
to: number;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* If no replaceRange, delete token before caret back to whitespace/start.
|
|
10
|
+
* Default true.
|
|
11
|
+
*/
|
|
12
|
+
replaceTriggerToken?: boolean;
|
|
13
|
+
/** Add whitespace after inserted content. Default true. */
|
|
14
|
+
trailingSpace?: boolean;
|
|
15
|
+
};
|
|
16
|
+
export declare const PROMPT_COMPOSER_COMMAND_CHIP_CLASS = "prompt-composer-command-chip";
|
|
17
|
+
export type PromptComposerHandle = {
|
|
18
|
+
insertAtCaret: (content: string | JSONContent, options?: PromptComposerInsertOptions) => void;
|
|
19
|
+
focus: () => void;
|
|
20
|
+
reset: () => void;
|
|
21
|
+
getText: () => string;
|
|
22
|
+
setContent: (text: string, options?: {
|
|
23
|
+
focus?: boolean;
|
|
24
|
+
atEnd?: boolean;
|
|
25
|
+
}) => void;
|
|
26
|
+
getEditor: () => Editor;
|
|
27
|
+
};
|
|
28
|
+
export declare function getPromptComposerTokenRangeBeforePos(editor: Editor, pos: number): {
|
|
29
|
+
from: number;
|
|
30
|
+
to: number;
|
|
31
|
+
};
|
|
32
|
+
export declare function promptComposerChipHtml(text: string, className?: string): string;
|
|
33
|
+
export type PromptComposerMentionNodeInput = {
|
|
34
|
+
id: string;
|
|
35
|
+
label?: string;
|
|
36
|
+
className?: string | null;
|
|
37
|
+
color?: string | null;
|
|
38
|
+
slashChar?: string;
|
|
39
|
+
};
|
|
40
|
+
export declare function promptComposerMentionNode(input: PromptComposerMentionNodeInput): JSONContent;
|
|
41
|
+
export declare function insertPromptComposerContentAtCaret(editor: Editor, content: string | JSONContent, options?: PromptComposerInsertOptions): void;
|
|
42
|
+
export declare function createPromptComposerHandle(editor: Editor): PromptComposerHandle;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type Editor } from '@tiptap/core';
|
|
2
|
+
import type { SlashCommandItem, SlashOnItemCommand } from '../../tiptap/slash-mention';
|
|
3
|
+
export type UsePromptComposerEditorOptions = {
|
|
4
|
+
disabled: boolean;
|
|
5
|
+
placeholder?: string;
|
|
6
|
+
slashCommandItems?: SlashCommandItem[];
|
|
7
|
+
onSlashItemCommand?: SlashOnItemCommand;
|
|
8
|
+
prefillMessage?: string | null;
|
|
9
|
+
attachmentsCount?: number;
|
|
10
|
+
allowEnterSubmit: boolean;
|
|
11
|
+
onSubmit?: (text: string, editor: Editor) => void;
|
|
12
|
+
onChange?: (text: string, editor: Editor) => void;
|
|
13
|
+
};
|
|
14
|
+
export type UsePromptComposerEditorResult = {
|
|
15
|
+
editor: Editor | null;
|
|
16
|
+
text: string;
|
|
17
|
+
trimmedText: string;
|
|
18
|
+
};
|
|
19
|
+
export declare function usePromptComposerEditor({ disabled, placeholder, slashCommandItems, onSlashItemCommand, prefillMessage, attachmentsCount, allowEnterSubmit, onSubmit, onChange, }: UsePromptComposerEditorOptions): UsePromptComposerEditorResult;
|
|
@@ -33,6 +33,7 @@ export * from './Portal/Portal';
|
|
|
33
33
|
export * from './PopupMenu/PopupMenu';
|
|
34
34
|
export * from './Progress/Progress';
|
|
35
35
|
export * from './ProgressCircular/ProgressCircular';
|
|
36
|
+
export * from './PromptComposer';
|
|
36
37
|
export * from './RadioButton/RadioButton';
|
|
37
38
|
export * from './RadioGroup/RadioGroup';
|
|
38
39
|
export * from './Router/Router';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { RefObject } from 'react';
|
|
2
|
+
import type { SlashCommandItem } from './types';
|
|
3
|
+
export type SlashSuggestionListHandle = {
|
|
4
|
+
onKeyboardEvent: (event: KeyboardEvent) => boolean;
|
|
5
|
+
};
|
|
6
|
+
export type SlashSuggestionListProps = {
|
|
7
|
+
items: SlashCommandItem[];
|
|
8
|
+
command: (item: SlashCommandItem) => void;
|
|
9
|
+
listHandleRef: RefObject<SlashSuggestionListHandle | null>;
|
|
10
|
+
};
|
|
11
|
+
export declare function SlashSuggestionList(props: SlashSuggestionListProps): JSX.Element;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { MutableRefObject } from 'react';
|
|
2
|
+
import type { SuggestionProps } from '@tiptap/suggestion';
|
|
3
|
+
import { type SlashSuggestionListHandle } from './SlashSuggestionList';
|
|
4
|
+
import type { CreateSlashMentionExtensionOptions, SlashCommandItem, SlashSuggestionPlacement } from './types';
|
|
5
|
+
export declare function slashMentionSuggestionRender(uiRef: MutableRefObject<SlashSuggestionListHandle | null>, placement?: SlashSuggestionPlacement): {
|
|
6
|
+
onStart?: (props: SuggestionProps<SlashCommandItem, SlashCommandItem>) => void;
|
|
7
|
+
onUpdate?: (props: SuggestionProps<SlashCommandItem, SlashCommandItem>) => void;
|
|
8
|
+
onExit?: (props: SuggestionProps<SlashCommandItem, SlashCommandItem>) => void;
|
|
9
|
+
onKeyDown?: (p: {
|
|
10
|
+
view: unknown;
|
|
11
|
+
event: KeyboardEvent;
|
|
12
|
+
range: {
|
|
13
|
+
from: number;
|
|
14
|
+
to: number;
|
|
15
|
+
};
|
|
16
|
+
}) => boolean;
|
|
17
|
+
};
|
|
18
|
+
export type CreateSlashMentionExtensionConfiguredOptions = CreateSlashMentionExtensionOptions & {
|
|
19
|
+
onSuggestionUiActiveChange?: (active: boolean) => void;
|
|
20
|
+
};
|
|
21
|
+
export declare function createSlashMentionExtension({ items: resolvedItems, slashChar, pluginKey, onItemCommand, suggestionPlacement, onSuggestionUiActiveChange, }: CreateSlashMentionExtensionConfiguredOptions): import("@tiptap/core").Node<import("@tiptap/extension-mention").MentionOptions<any, import("@tiptap/extension-mention").MentionNodeAttrs>, any>;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { SlashCommandItem } from './types';
|
|
2
|
+
/** Empty default; app passes slashCommandItems to enable menu. */
|
|
3
|
+
export declare const DEFAULT_CHAT_SLASH_ITEMS: SlashCommandItem[];
|
|
4
|
+
export declare function filterSlashItems(items: SlashCommandItem[], query: string): SlashCommandItem[];
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type { SlashCommandItem, SlashOnItemCommand, SlashItemCommandContext, SlashSuggestionPlacement, CreateSlashMentionExtensionOptions, } from './types';
|
|
2
|
+
export { DEFAULT_CHAT_SLASH_ITEMS, filterSlashItems, } from './defaultChatSlashItems';
|
|
3
|
+
export { createSlashMentionExtension, slashMentionSuggestionRender, } from './createSlashMentionExtension';
|
|
4
|
+
export type { CreateSlashMentionExtensionConfiguredOptions } from './createSlashMentionExtension';
|
|
5
|
+
export type { SlashSuggestionListHandle } from './SlashSuggestionList';
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Editor, Range } from '@tiptap/core';
|
|
2
|
+
export type SlashCommandItem = {
|
|
3
|
+
id: string;
|
|
4
|
+
label: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
/** Extra class on inserted mention chip (merged with `slash-mention`). */
|
|
7
|
+
className?: string;
|
|
8
|
+
/** CSS color for chip text; background uses 30% color blend. */
|
|
9
|
+
color?: string;
|
|
10
|
+
};
|
|
11
|
+
export type SlashItemCommandContext = {
|
|
12
|
+
item: SlashCommandItem;
|
|
13
|
+
/** Present when picked from slash menu; omitted on submit match. */
|
|
14
|
+
editor?: Editor;
|
|
15
|
+
range?: Range;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Return true to skip default mention insert and handle command in app.
|
|
19
|
+
*/
|
|
20
|
+
export type SlashOnItemCommand = (ctx: SlashItemCommandContext) => boolean;
|
|
21
|
+
export type SlashSuggestionPlacement = 'below' | 'above' | 'auto';
|
|
22
|
+
export type CreateSlashMentionExtensionOptions = {
|
|
23
|
+
items: SlashCommandItem[];
|
|
24
|
+
slashChar?: string;
|
|
25
|
+
pluginKey?: import('@tiptap/pm/state').PluginKey;
|
|
26
|
+
onItemCommand?: SlashOnItemCommand;
|
|
27
|
+
suggestionPlacement?: SlashSuggestionPlacement;
|
|
28
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@homecode/ui",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.3.0",
|
|
4
4
|
"description": "React UI components library",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"tests": "jest",
|
|
@@ -60,6 +60,13 @@
|
|
|
60
60
|
"@homecode/ui": "^4.17.2",
|
|
61
61
|
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.10",
|
|
62
62
|
"@rollup/plugin-typescript": "^11.0.0",
|
|
63
|
+
"@tiptap/core": "^3.22.1",
|
|
64
|
+
"@tiptap/extension-mention": "^3.22.1",
|
|
65
|
+
"@tiptap/extensions": "^3.22.1",
|
|
66
|
+
"@tiptap/pm": "^3.22.1",
|
|
67
|
+
"@tiptap/react": "^3.22.1",
|
|
68
|
+
"@tiptap/starter-kit": "^3.22.1",
|
|
69
|
+
"@tiptap/suggestion": "^3.22.1",
|
|
63
70
|
"@svgr/webpack": "^8.1.0",
|
|
64
71
|
"classnames": "^2.3.2",
|
|
65
72
|
"compareq": "^1.2.2",
|
package/.cursor/debug-8c6f78.log
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:handleFocus","message":"popup opening (focus)","data":{"scrollTop":0},"hypothesisId":"C","timestamp":1771711527049}
|
|
2
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":true,"currentFilter":"","totalCount":0,"itemsLen":20,"willFetch":true},"hypothesisId":"B","timestamp":1771711527054}
|
|
3
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:fetchOptionsCore","message":"setScrollTop(0) initial items","data":{"filter":"","offset":0,"totalCount":0},"hypothesisId":"B","timestamp":1771711527555}
|
|
4
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":true,"currentFilter":"","totalCount":200,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711527556}
|
|
5
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:fetchOptionsCore-RAF","message":"setScrollTop(undefined) clear","data":{"filter":"","offset":0},"hypothesisId":"E","timestamp":1771711527557}
|
|
6
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:handleBlur","message":"popup closing (blur)","data":{},"hypothesisId":"A","timestamp":1771711528848}
|
|
7
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":false,"currentFilter":"","totalCount":200,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711528850}
|
|
8
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:handleSelect","message":"select","data":{"selectable":true,"label":"Option 15"},"hypothesisId":"A","timestamp":1771711528971}
|
|
9
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:handleFocus","message":"popup opening (focus)","data":{"savedScrollTop":521.1111450195312},"hypothesisId":"C","timestamp":1771711532390}
|
|
10
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":true,"currentFilter":"","totalCount":200,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711532394}
|
|
11
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:handleBlur","message":"popup closing (blur)","data":{},"hypothesisId":"A","timestamp":1771711535314}
|
|
12
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":false,"currentFilter":"","totalCount":200,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711535317}
|
|
13
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:handleSelect","message":"select","data":{"selectable":true,"label":"Option 27"},"hypothesisId":"A","timestamp":1771711535455}
|
|
14
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:handleFocus","message":"popup opening (focus)","data":{"savedScrollTop":962.2222290039062},"hypothesisId":"C","timestamp":1771711540906}
|
|
15
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":true,"currentFilter":"","totalCount":200,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711540911}
|
|
16
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:handleBlur","message":"popup closing (blur)","data":{},"hypothesisId":"A","timestamp":1771711542255}
|
|
17
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":false,"currentFilter":"","totalCount":200,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711542257}
|
|
18
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:handleFocus","message":"popup opening (focus)","data":{"savedScrollTop":962.2222290039062},"hypothesisId":"C","timestamp":1771711543181}
|
|
19
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":true,"currentFilter":"","totalCount":200,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711543185}
|
|
20
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:handleBlur","message":"popup closing (blur)","data":{},"hypothesisId":"A","timestamp":1771711543773}
|
|
21
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":false,"currentFilter":"","totalCount":200,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711543776}
|
|
22
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:handleFocus","message":"popup opening (focus)","data":{"savedScrollTop":962.2222290039062},"hypothesisId":"C","timestamp":1771711544455}
|
|
23
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":true,"currentFilter":"","totalCount":200,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711544459}
|
|
24
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:handleBlur","message":"popup closing (blur)","data":{},"hypothesisId":"A","timestamp":1771711545022}
|
|
25
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":false,"currentFilter":"","totalCount":200,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711545023}
|
|
26
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-value","message":"setScrollTop(0) value cleared","data":{"value":""},"hypothesisId":"D","timestamp":1771711551359}
|
|
27
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":false,"currentFilter":"","totalCount":200,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711551359}
|
|
28
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":false,"currentFilter":"","totalCount":0,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711551360}
|
|
29
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-value","message":"setScrollTop(0) value cleared","data":{"value":""},"hypothesisId":"D","timestamp":1771711552110}
|
|
30
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":false,"currentFilter":"","totalCount":0,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711552111}
|
|
31
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-value","message":"setScrollTop(0) value cleared","data":{"value":""},"hypothesisId":"D","timestamp":1771711552853}
|
|
32
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":false,"currentFilter":"","totalCount":0,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711552853}
|
|
33
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-value","message":"setScrollTop(0) value cleared","data":{"value":""},"hypothesisId":"D","timestamp":1771711553442}
|
|
34
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":false,"currentFilter":"","totalCount":0,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711553443}
|
|
35
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-value","message":"setScrollTop(0) value cleared","data":{"value":""},"hypothesisId":"D","timestamp":1771711553951}
|
|
36
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":false,"currentFilter":"","totalCount":0,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711553951}
|
|
37
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-value","message":"setScrollTop(0) value cleared","data":{"value":""},"hypothesisId":"D","timestamp":1771711554564}
|
|
38
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":false,"currentFilter":"","totalCount":0,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711554564}
|
|
39
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-value","message":"setScrollTop(0) value cleared","data":{"value":""},"hypothesisId":"D","timestamp":1771711555318}
|
|
40
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":false,"currentFilter":"","totalCount":0,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711555319}
|
|
41
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-value","message":"setScrollTop(0) value cleared","data":{"value":""},"hypothesisId":"D","timestamp":1771711555975}
|
|
42
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":false,"currentFilter":"","totalCount":0,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711555975}
|
|
43
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":false,"currentFilter":"","totalCount":0,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711556573}
|
|
44
|
-
{"sessionId":"8c6f78","location":"Autocomplete.tsx:useEffect-open","message":"open/fetch effect","data":{"open":false,"currentFilter":"","totalCount":0,"itemsLen":20,"willFetch":false},"hypothesisId":"B","timestamp":1771711557126}
|
package/.cursor/debug-a8590a.log
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
{"sessionId":"a8590a","location":"Autocomplete.tsx:optionsList","message":"computedTotalCount","data":{"currentFilter":"","displayItemsLen":20,"totalCount":0,"computedTotalCount":20},"hypothesisId":"H2","timestamp":1771542687208}
|
|
2
|
-
{"sessionId":"a8590a","location":"Autocomplete.tsx:optionsList","message":"computedTotalCount","data":{"currentFilter":"","displayItemsLen":20,"totalCount":0,"computedTotalCount":20},"hypothesisId":"H2","timestamp":1771542690350}
|
|
3
|
-
{"sessionId":"a8590a","location":"Autocomplete.tsx:optionsList","message":"computedTotalCount","data":{"currentFilter":"","displayItemsLen":20,"totalCount":0,"computedTotalCount":20},"hypothesisId":"H2","timestamp":1771542690360}
|
|
4
|
-
{"sessionId":"a8590a","location":"Autocomplete.tsx:optionsList","message":"computedTotalCount","data":{"currentFilter":"","displayItemsLen":20,"totalCount":0,"computedTotalCount":20},"hypothesisId":"H2","timestamp":1771542690361}
|
|
5
|
-
{"sessionId":"a8590a","location":"Autocomplete.tsx:optionsList","message":"computedTotalCount","data":{"currentFilter":"","displayItemsLen":20,"totalCount":0,"computedTotalCount":20},"hypothesisId":"H2","timestamp":1771542691187}
|
|
6
|
-
{"sessionId":"a8590a","location":"Autocomplete.tsx:optionsList","message":"computedTotalCount","data":{"currentFilter":"","displayItemsLen":20,"totalCount":0,"computedTotalCount":20},"hypothesisId":"H2","timestamp":1771542691591}
|
|
7
|
-
{"sessionId":"a8590a","location":"Autocomplete.tsx:optionsList","message":"computedTotalCount","data":{"currentFilter":"","displayItemsLen":20,"totalCount":0,"computedTotalCount":20},"hypothesisId":"H2","timestamp":1771542691685}
|
|
8
|
-
{"sessionId":"a8590a","location":"Autocomplete.tsx:optionsList","message":"computedTotalCount","data":{"currentFilter":"","displayItemsLen":20,"totalCount":0,"computedTotalCount":20},"hypothesisId":"H2","timestamp":1771542691785}
|
|
9
|
-
{"sessionId":"a8590a","location":"Autocomplete.tsx:optionsList","message":"computedTotalCount","data":{"currentFilter":"","displayItemsLen":20,"totalCount":0,"computedTotalCount":20},"hypothesisId":"H2","timestamp":1771542692007}
|
|
10
|
-
{"sessionId":"a8590a","location":"Autocomplete.tsx:optionsList","message":"computedTotalCount","data":{"currentFilter":"","displayItemsLen":20,"totalCount":0,"computedTotalCount":20},"hypothesisId":"H2","timestamp":1771542692040}
|
|
11
|
-
{"sessionId":"a8590a","location":"Autocomplete.tsx:optionsList","message":"computedTotalCount","data":{"currentFilter":"","displayItemsLen":20,"totalCount":0,"computedTotalCount":20},"hypothesisId":"H2","timestamp":1771542692065}
|
|
12
|
-
{"sessionId":"a8590a","location":"Autocomplete.tsx:optionsList","message":"computedTotalCount","data":{"currentFilter":"","displayItemsLen":20,"totalCount":0,"computedTotalCount":20},"hypothesisId":"H2","timestamp":1771542692082}
|
|
13
|
-
{"sessionId":"a8590a","location":"Autocomplete.tsx:optionsList","message":"computedTotalCount","data":{"currentFilter":"","displayItemsLen":20,"totalCount":0,"computedTotalCount":20},"hypothesisId":"H2","timestamp":1771542692099}
|
|
14
|
-
{"sessionId":"a8590a","location":"Autocomplete.tsx:optionsList","message":"computedTotalCount","data":{"currentFilter":"","displayItemsLen":20,"totalCount":0,"computedTotalCount":20},"hypothesisId":"H2","timestamp":1771542692116}
|
|
15
|
-
{"sessionId":"a8590a","location":"Autocomplete.tsx:optionsList","message":"computedTotalCount","data":{"currentFilter":"","displayItemsLen":20,"totalCount":0,"computedTotalCount":20},"hypothesisId":"H2","timestamp":1771542692132}
|
|
16
|
-
{"sessionId":"a8590a","location":"Autocomplete.tsx:optionsList","message":"computedTotalCount","data":{"currentFilter":"","displayItemsLen":20,"totalCount":0,"computedTotalCount":20},"hypothesisId":"H2","timestamp":1771542692149}
|
|
17
|
-
{"sessionId":"a8590a","location":"Autocomplete.tsx:optionsList","message":"computedTotalCount","data":{"currentFilter":"","displayItemsLen":20,"totalCount":0,"computedTotalCount":20},"hypothesisId":"H2","timestamp":1771542692173}
|
|
18
|
-
{"sessionId":"a8590a","location":"Autocomplete.tsx:optionsList","message":"computedTotalCount","data":{"currentFilter":"","displayItemsLen":20,"totalCount":0,"computedTotalCount":20},"hypothesisId":"H2","timestamp":1771542692190}
|
|
19
|
-
{"sessionId":"a8590a","location":"Autocomplete.tsx:optionsList","message":"computedTotalCount","data":{"currentFilter":"","displayItemsLen":20,"totalCount":0,"computedTotalCount":20},"hypothesisId":"H2","timestamp":1771542692215}
|
|
20
|
-
{"sessionId":"a8590a","location":"Autocomplete.tsx:optionsList","message":"computedTotalCount","data":{"currentFilter":"","displayItemsLen":20,"totalCount":0,"computedTotalCount":20},"hypothesisId":"H2","timestamp":1771542692240}
|
|
21
|
-
{"sessionId":"a8590a","location":"Autocomplete.tsx:optionsList","message":"computedTotalCount","data":{"currentFilter":"","displayItemsLen":20,"totalCount":0,"computedTotalCount":20},"hypothesisId":"H2","timestamp":1771542692273}
|
|
22
|
-
{"sessionId":"a8590a","location":"Autocomplete.tsx:optionsList","message":"computedTotalCount","data":{"currentFilter":"","displayItemsLen":20,"totalCount":0,"computedTotalCount":20},"hypothesisId":"H2","timestamp":1771542692315}
|
|
23
|
-
{"sessionId":"a8590a","location":"Autocomplete.tsx:optionsList","message":"computedTotalCount","data":{"currentFilter":"","displayItemsLen":20,"totalCount":0,"computedTotalCount":20},"hypothesisId":"H2","timestamp":1771542692356}
|
|
24
|
-
{"sessionId":"a8590a","location":"Virtualized.tsx:checkIfEnd","message":"checkIfEnd","data":{"itemsCount":20,"totalCount":20,"lastScrollEndIndex":0,"willSkipItemsEqTotal":true,"willSkipItemsLtLast":false},"hypothesisId":"H2","timestamp":1771542692464}
|
|
25
|
-
{"sessionId":"a8590a","location":"Virtualized.tsx:checkIfEnd","message":"checkIfEnd","data":{"itemsCount":20,"totalCount":20,"lastScrollEndIndex":0,"willSkipItemsEqTotal":true,"willSkipItemsLtLast":false},"hypothesisId":"H2","timestamp":1771542692731}
|
|
26
|
-
{"sessionId":"a8590a","location":"Autocomplete.tsx:optionsList","message":"computedTotalCount","data":{"currentFilter":"","displayItemsLen":20,"totalCount":0,"computedTotalCount":20},"hypothesisId":"H2","timestamp":1771542694211}
|