@choice-ui/react 1.4.5 → 1.4.6
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/components/context-input/dist/index.d.ts +123 -2
- package/dist/components/context-input/src/index.d.ts +2 -0
- package/dist/components/context-input/src/utils/mention-spacing.js +27 -1
- package/dist/components/context-input/src/utils/slate-converters.js +67 -1
- package/dist/index.js +21 -0
- package/package.json +1 -1
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { default as React__default, ComponentType } from 'react';
|
|
2
2
|
import { IconButtonProps } from '../../icon-button/src';
|
|
3
|
-
import { RenderElementProps } from 'slate-react';
|
|
3
|
+
import { RenderElementProps, ReactEditor } from 'slate-react';
|
|
4
|
+
import { Editor, Range, Descendant } from 'slate';
|
|
5
|
+
import { HistoryEditor } from 'slate-history';
|
|
4
6
|
import * as React$1 from 'react';
|
|
5
7
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
6
8
|
|
|
@@ -122,4 +124,123 @@ interface ContextInputComponent extends React__default.ForwardRefExoticComponent
|
|
|
122
124
|
}
|
|
123
125
|
declare const ContextInput: ContextInputComponent;
|
|
124
126
|
|
|
125
|
-
|
|
127
|
+
type ContextEditor = Editor & ReactEditor & HistoryEditor;
|
|
128
|
+
|
|
129
|
+
interface MentionSearchState {
|
|
130
|
+
index: number;
|
|
131
|
+
isSearching: boolean;
|
|
132
|
+
loading: boolean;
|
|
133
|
+
position: {
|
|
134
|
+
x: number;
|
|
135
|
+
y: number;
|
|
136
|
+
} | null;
|
|
137
|
+
query: string;
|
|
138
|
+
suggestions: ContextMentionItemProps[];
|
|
139
|
+
target: Range | null;
|
|
140
|
+
trigger: string;
|
|
141
|
+
}
|
|
142
|
+
interface UseMentionsProps {
|
|
143
|
+
editor: ContextEditor;
|
|
144
|
+
maxSuggestions?: number;
|
|
145
|
+
mentionPrefix?: string;
|
|
146
|
+
onMentionSelect?: (mention: ContextMentionItemProps, trigger: string) => void;
|
|
147
|
+
onSearchClose?: () => void;
|
|
148
|
+
triggers: ContextMentionTrigger[];
|
|
149
|
+
}
|
|
150
|
+
declare function useMentions({ editor, triggers, maxSuggestions, mentionPrefix, onMentionSelect, onSearchClose, }: UseMentionsProps): {
|
|
151
|
+
searchState: MentionSearchState;
|
|
152
|
+
checkMentionSearch: () => void;
|
|
153
|
+
insertMention: (mention: ContextMentionItemProps) => void;
|
|
154
|
+
handleKeyDown: (event: React$1.KeyboardEvent<Element>) => boolean;
|
|
155
|
+
closeMentionSearch: () => void;
|
|
156
|
+
selectMention: (index: number) => void;
|
|
157
|
+
selectNextMention: () => void;
|
|
158
|
+
selectPreviousMention: () => void;
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
interface UseContextInputProps {
|
|
162
|
+
autoFocus?: boolean;
|
|
163
|
+
editor?: ContextEditor;
|
|
164
|
+
onChange?: (value: ContextInputValue) => void;
|
|
165
|
+
value?: ContextInputValue;
|
|
166
|
+
}
|
|
167
|
+
declare const useContextInput: ({ value, onChange, editor, autoFocus }: UseContextInputProps) => {
|
|
168
|
+
slateValue: Descendant[];
|
|
169
|
+
handleChange: (newValue: Descendant[]) => void;
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
declare const useContextInputEditor: () => ContextEditor;
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Convert SlateJS node array to string
|
|
176
|
+
* Mention nodes are converted to {{#context#}}{{#id.text#}} format
|
|
177
|
+
*/
|
|
178
|
+
declare function convertSlateToText(nodes: Descendant[]): string;
|
|
179
|
+
/**
|
|
180
|
+
* Convert string to SlateJS node array
|
|
181
|
+
* Supports parsing {{#context#}}{{#id.text#}} format to mention nodes
|
|
182
|
+
*/
|
|
183
|
+
declare function convertTextToSlate(text: string): Descendant[];
|
|
184
|
+
/**
|
|
185
|
+
* Interface for mention resolver function
|
|
186
|
+
*/
|
|
187
|
+
interface MentionResolver {
|
|
188
|
+
(mentionId: string): Promise<{
|
|
189
|
+
label: string;
|
|
190
|
+
metadata?: Record<string, unknown>;
|
|
191
|
+
type: string;
|
|
192
|
+
}>;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Advanced version: supports async mention info resolution
|
|
196
|
+
*/
|
|
197
|
+
declare function convertTextToSlateWithResolver(text: string, mentionResolver?: MentionResolver): Promise<Descendant[]>;
|
|
198
|
+
|
|
199
|
+
declare const extractTextWithMentions: (nodes: Descendant[]) => {
|
|
200
|
+
text: string;
|
|
201
|
+
mentionsData: {
|
|
202
|
+
element: ContextMentionElement;
|
|
203
|
+
endIndex: number;
|
|
204
|
+
startIndex: number;
|
|
205
|
+
}[];
|
|
206
|
+
};
|
|
207
|
+
declare const parseTextWithMentions: (text: string, mentions: MentionMatch[]) => Descendant[];
|
|
208
|
+
|
|
209
|
+
declare const extractMentionContext: (text: string, startIndex: number, endIndex: number, contextLength?: number) => {
|
|
210
|
+
mentionText: string;
|
|
211
|
+
fullContext: string;
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Check if a space should be inserted before the current position
|
|
216
|
+
* @param editor - SlateJS editor instance
|
|
217
|
+
* @returns Whether a leading space should be added
|
|
218
|
+
*/
|
|
219
|
+
declare function shouldInsertSpaceBefore(editor: Editor): boolean;
|
|
220
|
+
/**
|
|
221
|
+
* Check if a space should be inserted after the current position
|
|
222
|
+
* @param editor - SlateJS editor instance
|
|
223
|
+
* @returns Whether a trailing space should be added
|
|
224
|
+
*/
|
|
225
|
+
declare function shouldInsertSpaceAfter(editor: Editor): boolean;
|
|
226
|
+
/**
|
|
227
|
+
* Smartly insert space at current position (leading space)
|
|
228
|
+
* @param editor - SlateJS editor instance
|
|
229
|
+
* @returns Whether a space was inserted
|
|
230
|
+
*/
|
|
231
|
+
declare function insertSpaceBeforeIfNeeded(editor: Editor): boolean;
|
|
232
|
+
/**
|
|
233
|
+
* Smartly insert space at current position (trailing space)
|
|
234
|
+
* @param editor - SlateJS editor instance
|
|
235
|
+
* @returns Whether a space was inserted
|
|
236
|
+
*/
|
|
237
|
+
declare function insertSpaceAfterIfNeeded(editor: Editor): boolean;
|
|
238
|
+
/**
|
|
239
|
+
* Insert smart spacing for mention
|
|
240
|
+
* This function intelligently adds spaces before/after mention insertion based on context
|
|
241
|
+
* @param editor - SlateJS editor instance
|
|
242
|
+
* @param beforeInsertion - Callback to execute before content insertion
|
|
243
|
+
*/
|
|
244
|
+
declare function insertWithSmartSpacing(editor: Editor, beforeInsertion: () => void): void;
|
|
245
|
+
|
|
246
|
+
export { ContextInput, type ContextInputProps, type ContextInputRef, type ContextInputValue, type ContextMentionElement, type ContextMentionItemProps, type ContextMentionProps, type ContextMentionTrigger, CopyButton, InsertMentionsButton, convertSlateToText, convertTextToSlate, convertTextToSlateWithResolver, extractMentionContext, extractTextWithMentions, insertSpaceAfterIfNeeded, insertSpaceBeforeIfNeeded, insertWithSmartSpacing, parseTextWithMentions, shouldInsertSpaceAfter, shouldInsertSpaceBefore, useContextInput, useContextInputEditor, useMentions };
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export { ContextInput } from './context-input';
|
|
2
2
|
export { InsertMentionsButton, CopyButton } from './components';
|
|
3
|
+
export { useContextInput, useMentions, useContextInputEditor } from './hooks';
|
|
4
|
+
export { shouldInsertSpaceBefore, shouldInsertSpaceAfter, insertSpaceBeforeIfNeeded, insertSpaceAfterIfNeeded, insertWithSmartSpacing, convertSlateToText, convertTextToSlate, convertTextToSlateWithResolver, extractTextWithMentions, parseTextWithMentions, extractMentionContext, } from './utils';
|
|
3
5
|
export type { ContextInputProps, ContextInputValue, ContextMentionElement, ContextInputRef, ContextMentionProps, ContextMentionItemProps, ContextMentionTrigger, } from './types';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Editor, Transforms } from "slate";
|
|
2
2
|
function shouldInsertSpaceBefore(editor) {
|
|
3
3
|
const { selection } = editor;
|
|
4
4
|
if (!selection) {
|
|
@@ -16,6 +16,23 @@ function shouldInsertSpaceBefore(editor) {
|
|
|
16
16
|
}
|
|
17
17
|
return false;
|
|
18
18
|
}
|
|
19
|
+
function shouldInsertSpaceAfter(editor) {
|
|
20
|
+
const { selection } = editor;
|
|
21
|
+
if (!selection) {
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
const after = Editor.after(editor, selection.anchor, { unit: "character" });
|
|
26
|
+
if (after) {
|
|
27
|
+
const afterRange = Editor.range(editor, selection.anchor, after);
|
|
28
|
+
const afterText = Editor.string(editor, afterRange);
|
|
29
|
+
return afterText !== "" && afterText !== " " && afterText !== "\n";
|
|
30
|
+
}
|
|
31
|
+
} catch {
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
19
36
|
function insertSpaceBeforeIfNeeded(editor) {
|
|
20
37
|
if (shouldInsertSpaceBefore(editor)) {
|
|
21
38
|
Transforms.insertText(editor, " ");
|
|
@@ -23,6 +40,13 @@ function insertSpaceBeforeIfNeeded(editor) {
|
|
|
23
40
|
}
|
|
24
41
|
return false;
|
|
25
42
|
}
|
|
43
|
+
function insertSpaceAfterIfNeeded(editor) {
|
|
44
|
+
if (shouldInsertSpaceAfter(editor)) {
|
|
45
|
+
Transforms.insertText(editor, " ");
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
26
50
|
function insertWithSmartSpacing(editor, beforeInsertion) {
|
|
27
51
|
const needsSpaceBefore = shouldInsertSpaceBefore(editor);
|
|
28
52
|
if (needsSpaceBefore) {
|
|
@@ -32,7 +56,9 @@ function insertWithSmartSpacing(editor, beforeInsertion) {
|
|
|
32
56
|
Transforms.insertText(editor, " ");
|
|
33
57
|
}
|
|
34
58
|
export {
|
|
59
|
+
insertSpaceAfterIfNeeded,
|
|
35
60
|
insertSpaceBeforeIfNeeded,
|
|
36
61
|
insertWithSmartSpacing,
|
|
62
|
+
shouldInsertSpaceAfter,
|
|
37
63
|
shouldInsertSpaceBefore
|
|
38
64
|
};
|
|
@@ -98,7 +98,73 @@ function isMentionElement(node) {
|
|
|
98
98
|
const nodeAny = node;
|
|
99
99
|
return nodeAny.type === "mention";
|
|
100
100
|
}
|
|
101
|
+
async function convertTextToSlateWithResolver(text, mentionResolver) {
|
|
102
|
+
if (!text || text.trim() === "") {
|
|
103
|
+
return [{ type: "paragraph", children: [{ text: "" }] }];
|
|
104
|
+
}
|
|
105
|
+
const lines = text.split("\n");
|
|
106
|
+
const resolvedLines = await Promise.all(
|
|
107
|
+
lines.map((line) => parseLineToNodesWithResolver(line, mentionResolver))
|
|
108
|
+
);
|
|
109
|
+
return resolvedLines.map((children) => ({
|
|
110
|
+
type: "paragraph",
|
|
111
|
+
children
|
|
112
|
+
}));
|
|
113
|
+
}
|
|
114
|
+
async function parseLineToNodesWithResolver(line, mentionResolver) {
|
|
115
|
+
const mentionRegex = /\{\{#([^}]+?)(?:\.text)?#\}\}/g;
|
|
116
|
+
const nodes = [];
|
|
117
|
+
let lastIndex = 0;
|
|
118
|
+
const matches = [];
|
|
119
|
+
let match;
|
|
120
|
+
while ((match = mentionRegex.exec(line)) !== null) {
|
|
121
|
+
matches.push({ ...match });
|
|
122
|
+
}
|
|
123
|
+
for (const match2 of matches) {
|
|
124
|
+
const [fullMatch, mentionId] = match2;
|
|
125
|
+
const matchStart = match2.index;
|
|
126
|
+
const matchEnd = match2.index + fullMatch.length;
|
|
127
|
+
if (matchStart > lastIndex) {
|
|
128
|
+
const textBefore = line.slice(lastIndex, matchStart);
|
|
129
|
+
if (textBefore) {
|
|
130
|
+
nodes.push({ text: textBefore });
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
let mentionInfo = {
|
|
134
|
+
label: `User ${mentionId}`,
|
|
135
|
+
type: "user"
|
|
136
|
+
};
|
|
137
|
+
if (mentionResolver) {
|
|
138
|
+
try {
|
|
139
|
+
mentionInfo = await mentionResolver(mentionId);
|
|
140
|
+
} catch (error) {
|
|
141
|
+
console.warn(`Failed to resolve mention ${mentionId}:`, error);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const mentionNode = {
|
|
145
|
+
type: "mention",
|
|
146
|
+
mentionType: mentionInfo.type,
|
|
147
|
+
mentionId,
|
|
148
|
+
mentionLabel: mentionInfo.label,
|
|
149
|
+
mentionData: mentionInfo.metadata || {},
|
|
150
|
+
children: [{ text: "" }]
|
|
151
|
+
};
|
|
152
|
+
nodes.push(mentionNode);
|
|
153
|
+
lastIndex = matchEnd;
|
|
154
|
+
}
|
|
155
|
+
if (lastIndex < line.length) {
|
|
156
|
+
const textAfter = line.slice(lastIndex);
|
|
157
|
+
if (textAfter) {
|
|
158
|
+
nodes.push({ text: textAfter });
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (nodes.length === 0) {
|
|
162
|
+
nodes.push({ text: line });
|
|
163
|
+
}
|
|
164
|
+
return nodes;
|
|
165
|
+
}
|
|
101
166
|
export {
|
|
102
167
|
convertSlateToText,
|
|
103
|
-
convertTextToSlate
|
|
168
|
+
convertTextToSlate,
|
|
169
|
+
convertTextToSlateWithResolver
|
|
104
170
|
};
|
package/dist/index.js
CHANGED
|
@@ -81,6 +81,13 @@ import { useDragAndDrop } from "./components/conditions/src/hooks/use-drag-and-d
|
|
|
81
81
|
import { ContextInput } from "./components/context-input/src/context-input.js";
|
|
82
82
|
import { InsertMentionsButton } from "./components/context-input/src/components/insert-mentions-button.js";
|
|
83
83
|
import { CopyButton } from "./components/context-input/src/components/copy-button.js";
|
|
84
|
+
import { useContextInput } from "./components/context-input/src/hooks/use-context-input.js";
|
|
85
|
+
import { useMentions } from "./components/context-input/src/hooks/use-mentions.js";
|
|
86
|
+
import { useContextInputEditor } from "./components/context-input/src/hooks/use-context-input-editor.js";
|
|
87
|
+
import { insertSpaceAfterIfNeeded, insertSpaceBeforeIfNeeded, insertWithSmartSpacing, shouldInsertSpaceAfter, shouldInsertSpaceBefore } from "./components/context-input/src/utils/mention-spacing.js";
|
|
88
|
+
import { convertSlateToText, convertTextToSlate, convertTextToSlateWithResolver } from "./components/context-input/src/utils/slate-converters.js";
|
|
89
|
+
import { extractTextWithMentions, parseTextWithMentions } from "./components/context-input/src/utils/text-extraction.js";
|
|
90
|
+
import { extractMentionContext } from "./components/context-input/src/utils/context-extraction.js";
|
|
84
91
|
import { ContextMenu } from "./components/context-menu/src/context-menu.js";
|
|
85
92
|
import { Dialog } from "./components/dialog/src/dialog.js";
|
|
86
93
|
import { Dropdown } from "./components/dropdown/src/dropdown.js";
|
|
@@ -461,6 +468,9 @@ export {
|
|
|
461
468
|
commentsService,
|
|
462
469
|
commonDateFormats,
|
|
463
470
|
commonTimeFormats,
|
|
471
|
+
convertSlateToText,
|
|
472
|
+
convertTextToSlate,
|
|
473
|
+
convertTextToSlateWithResolver,
|
|
464
474
|
convertTwoDigitYear,
|
|
465
475
|
createCondition,
|
|
466
476
|
createConditionGroup,
|
|
@@ -482,6 +492,8 @@ export {
|
|
|
482
492
|
emojis,
|
|
483
493
|
englishMonths,
|
|
484
494
|
extractDigits,
|
|
495
|
+
extractMentionContext,
|
|
496
|
+
extractTextWithMentions,
|
|
485
497
|
findChildByType,
|
|
486
498
|
findClosestValidTime,
|
|
487
499
|
findCondition,
|
|
@@ -546,6 +558,9 @@ export {
|
|
|
546
558
|
handleShortcuts,
|
|
547
559
|
inferMonthFromValue,
|
|
548
560
|
inferSelectionMode,
|
|
561
|
+
insertSpaceAfterIfNeeded,
|
|
562
|
+
insertSpaceBeforeIfNeeded,
|
|
563
|
+
insertWithSmartSpacing,
|
|
549
564
|
isArray,
|
|
550
565
|
isBrowser,
|
|
551
566
|
isCalendarValueEqual,
|
|
@@ -592,6 +607,7 @@ export {
|
|
|
592
607
|
parseMonthName,
|
|
593
608
|
parseNaturalLanguage,
|
|
594
609
|
parseRelativeDate,
|
|
610
|
+
parseTextWithMentions,
|
|
595
611
|
parseYYMMDD,
|
|
596
612
|
parseYYYYMMDD,
|
|
597
613
|
parserConfig,
|
|
@@ -603,6 +619,8 @@ export {
|
|
|
603
619
|
renderSecondValueInput,
|
|
604
620
|
renderValueInput,
|
|
605
621
|
resolveLocale,
|
|
622
|
+
shouldInsertSpaceAfter,
|
|
623
|
+
shouldInsertSpaceBefore,
|
|
606
624
|
slateToMarkdown,
|
|
607
625
|
smartCorrectDate,
|
|
608
626
|
smartCorrectYear,
|
|
@@ -627,6 +645,8 @@ export {
|
|
|
627
645
|
useConfigData,
|
|
628
646
|
useConstRef,
|
|
629
647
|
useContainerData,
|
|
648
|
+
useContextInput,
|
|
649
|
+
useContextInputEditor,
|
|
630
650
|
useDateInput,
|
|
631
651
|
useDirection,
|
|
632
652
|
useDisableScroll,
|
|
@@ -646,6 +666,7 @@ export {
|
|
|
646
666
|
useLayoutData,
|
|
647
667
|
useLazyRef,
|
|
648
668
|
useLoader,
|
|
669
|
+
useMentions,
|
|
649
670
|
useMenuBaseRefs,
|
|
650
671
|
useMenuChildren,
|
|
651
672
|
useMenuFloating,
|
package/package.json
CHANGED