@choice-ui/react 1.4.5 → 1.4.7

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.
@@ -1,4 +1,4 @@
1
1
  export { AlertDialog } from './alert-dialog';
2
2
  export type { AlertDialogProps } from './alert-dialog';
3
3
  export { AlertDialogProvider } from './context';
4
- export { useAlertDialog, useAlertDialogProvider } from './hooks';
4
+ export { useAlertDialog, useAlertDialogProvider } from './hooks/use-alert-dialog';
@@ -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
- export { ContextInput, type ContextInputProps, type ContextInputRef, type ContextInputValue, type ContextMentionElement, type ContextMentionItemProps, type ContextMentionProps, type ContextMentionTrigger, CopyButton, InsertMentionsButton };
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 { Transforms, Editor } from "slate";
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@choice-ui/react",
3
- "version": "1.4.5",
3
+ "version": "1.4.7",
4
4
  "description": "A desktop-first React UI component library built for professional desktop applications with comprehensive documentation",
5
5
  "sideEffects": false,
6
6
  "type": "module",