@streamsai/ui 0.0.0-stage → 0.1.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.
Files changed (206) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +57 -2
  3. package/dist/components/ui/agent-avatar.d.ts +50 -0
  4. package/dist/components/ui/agent-avatar.js +38 -0
  5. package/dist/components/ui/alert-dialog.d.ts +12 -0
  6. package/dist/components/ui/alert-dialog.js +37 -0
  7. package/dist/components/ui/alert.d.ts +10 -0
  8. package/dist/components/ui/alert.js +28 -0
  9. package/dist/components/ui/assets/loader.json.js +1 -0
  10. package/dist/components/ui/avatar-frame.d.ts +11 -0
  11. package/dist/components/ui/avatar-frame.js +20 -0
  12. package/dist/components/ui/avatar.d.ts +23 -0
  13. package/dist/components/ui/avatar.js +54 -0
  14. package/dist/components/ui/badge.d.ts +7 -0
  15. package/dist/components/ui/badge.js +36 -0
  16. package/dist/components/ui/bar-list.d.ts +40 -0
  17. package/dist/components/ui/bar-list.js +37 -0
  18. package/dist/components/ui/breadcrumb.d.ts +8 -0
  19. package/dist/components/ui/breadcrumb.js +21 -0
  20. package/dist/components/ui/button-group.d.ts +10 -0
  21. package/dist/components/ui/button-group.js +41 -0
  22. package/dist/components/ui/button.d.ts +9 -0
  23. package/dist/components/ui/button.js +39 -0
  24. package/dist/components/ui/card.d.ts +9 -0
  25. package/dist/components/ui/card.js +25 -0
  26. package/dist/components/ui/checkbox.d.ts +3 -0
  27. package/dist/components/ui/checkbox.js +16 -0
  28. package/dist/components/ui/chip.d.ts +13 -0
  29. package/dist/components/ui/chip.js +22 -0
  30. package/dist/components/ui/clickable.d.ts +27 -0
  31. package/dist/components/ui/clickable.js +54 -0
  32. package/dist/components/ui/code-block.d.ts +68 -0
  33. package/dist/components/ui/code-block.js +112 -0
  34. package/dist/components/ui/code-view.d.ts +21 -0
  35. package/dist/components/ui/code-view.js +20 -0
  36. package/dist/components/ui/collapsible.d.ts +6 -0
  37. package/dist/components/ui/collapsible.js +18 -0
  38. package/dist/components/ui/combobox.d.ts +14 -0
  39. package/dist/components/ui/combobox.js +37 -0
  40. package/dist/components/ui/command.d.ts +15 -0
  41. package/dist/components/ui/command.js +34 -0
  42. package/dist/components/ui/context-menu.d.ts +21 -0
  43. package/dist/components/ui/context-menu.js +60 -0
  44. package/dist/components/ui/counter.d.ts +11 -0
  45. package/dist/components/ui/counter.js +20 -0
  46. package/dist/components/ui/dialog.d.ts +17 -0
  47. package/dist/components/ui/dialog.js +41 -0
  48. package/dist/components/ui/disabled-reason.d.ts +22 -0
  49. package/dist/components/ui/disabled-reason.js +16 -0
  50. package/dist/components/ui/dropdown-menu.d.ts +33 -0
  51. package/dist/components/ui/dropdown-menu.js +58 -0
  52. package/dist/components/ui/editable-text.d.ts +95 -0
  53. package/dist/components/ui/editable-text.js +191 -0
  54. package/dist/components/ui/heading.d.ts +24 -0
  55. package/dist/components/ui/heading.js +92 -0
  56. package/dist/components/ui/hover-card.d.ts +9 -0
  57. package/dist/components/ui/hover-card.js +16 -0
  58. package/dist/components/ui/icon-button.d.ts +23 -0
  59. package/dist/components/ui/icon-button.js +32 -0
  60. package/dist/components/ui/input.d.ts +3 -0
  61. package/dist/components/ui/input.js +8 -0
  62. package/dist/components/ui/kbd.d.ts +12 -0
  63. package/dist/components/ui/kbd.js +12 -0
  64. package/dist/components/ui/label.d.ts +3 -0
  65. package/dist/components/ui/label.js +7 -0
  66. package/dist/components/ui/loader.d.ts +19 -0
  67. package/dist/components/ui/loader.js +157 -0
  68. package/dist/components/ui/message-toolbar.d.ts +20 -0
  69. package/dist/components/ui/message-toolbar.js +17 -0
  70. package/dist/components/ui/modal.d.ts +30 -0
  71. package/dist/components/ui/modal.js +41 -0
  72. package/dist/components/ui/nav-item.d.ts +25 -0
  73. package/dist/components/ui/nav-item.js +66 -0
  74. package/dist/components/ui/panel-section.d.ts +22 -0
  75. package/dist/components/ui/panel-section.js +26 -0
  76. package/dist/components/ui/popover.d.ts +14 -0
  77. package/dist/components/ui/popover.js +30 -0
  78. package/dist/components/ui/progress.d.ts +5 -0
  79. package/dist/components/ui/progress.js +16 -0
  80. package/dist/components/ui/provider-badge.d.ts +22 -0
  81. package/dist/components/ui/provider-badge.js +38 -0
  82. package/dist/components/ui/radio-group.d.ts +5 -0
  83. package/dist/components/ui/radio-group.js +21 -0
  84. package/dist/components/ui/reply-summary.d.ts +16 -0
  85. package/dist/components/ui/reply-summary.js +8 -0
  86. package/dist/components/ui/resizable.d.ts +8 -0
  87. package/dist/components/ui/resizable.js +15 -0
  88. package/dist/components/ui/rich-text-editor.d.ts +447 -0
  89. package/dist/components/ui/rich-text-editor.js +2419 -0
  90. package/dist/components/ui/running-indicator.d.ts +17 -0
  91. package/dist/components/ui/running-indicator.js +34 -0
  92. package/dist/components/ui/sandboxed-frame.d.ts +29 -0
  93. package/dist/components/ui/sandboxed-frame.js +77 -0
  94. package/dist/components/ui/scroll-area.d.ts +14 -0
  95. package/dist/components/ui/scroll-area.js +17 -0
  96. package/dist/components/ui/section-header.d.ts +12 -0
  97. package/dist/components/ui/section-header.js +12 -0
  98. package/dist/components/ui/select.d.ts +15 -0
  99. package/dist/components/ui/select.js +40 -0
  100. package/dist/components/ui/separator.d.ts +3 -0
  101. package/dist/components/ui/separator.js +13 -0
  102. package/dist/components/ui/sheet.d.ts +23 -0
  103. package/dist/components/ui/sheet.js +48 -0
  104. package/dist/components/ui/shimmer-text.d.ts +26 -0
  105. package/dist/components/ui/shimmer-text.js +32 -0
  106. package/dist/components/ui/sidebar.d.ts +63 -0
  107. package/dist/components/ui/sidebar.js +283 -0
  108. package/dist/components/ui/skeleton.d.ts +14 -0
  109. package/dist/components/ui/skeleton.js +12 -0
  110. package/dist/components/ui/sonner.d.ts +4 -0
  111. package/dist/components/ui/sonner.js +14 -0
  112. package/dist/components/ui/spark-bars.d.ts +29 -0
  113. package/dist/components/ui/spark-bars.js +24 -0
  114. package/dist/components/ui/spinner.d.ts +16 -0
  115. package/dist/components/ui/spinner.js +26 -0
  116. package/dist/components/ui/stacked-bar.d.ts +37 -0
  117. package/dist/components/ui/stacked-bar.js +56 -0
  118. package/dist/components/ui/status-dot.d.ts +16 -0
  119. package/dist/components/ui/status-dot.js +32 -0
  120. package/dist/components/ui/switch.d.ts +5 -0
  121. package/dist/components/ui/switch.js +13 -0
  122. package/dist/components/ui/tabs.d.ts +14 -0
  123. package/dist/components/ui/tabs.js +55 -0
  124. package/dist/components/ui/text.d.ts +27 -0
  125. package/dist/components/ui/text.js +100 -0
  126. package/dist/components/ui/textarea.d.ts +3 -0
  127. package/dist/components/ui/textarea.js +7 -0
  128. package/dist/components/ui/theme-toggle.d.ts +21 -0
  129. package/dist/components/ui/theme-toggle.js +17 -0
  130. package/dist/components/ui/toggle-group.d.ts +6 -0
  131. package/dist/components/ui/toggle-group.js +12 -0
  132. package/dist/components/ui/tooltip.d.ts +11 -0
  133. package/dist/components/ui/tooltip.js +21 -0
  134. package/dist/components/ui/trace.d.ts +24 -0
  135. package/dist/components/ui/trace.js +57 -0
  136. package/dist/components/ui/trend-line.d.ts +93 -0
  137. package/dist/components/ui/trend-line.js +215 -0
  138. package/dist/components/ui/truncate.d.ts +30 -0
  139. package/dist/components/ui/truncate.js +54 -0
  140. package/dist/components/ui/viewer-shell.d.ts +55 -0
  141. package/dist/components/ui/viewer-shell.js +15 -0
  142. package/dist/components/ui/virtual-list.d.ts +91 -0
  143. package/dist/components/ui/virtual-list.js +406 -0
  144. package/dist/components/ui/visually-hidden.d.ts +15 -0
  145. package/dist/components/ui/visually-hidden.js +19 -0
  146. package/dist/direction/index.d.ts +19 -0
  147. package/dist/direction/index.js +32 -0
  148. package/dist/hooks/use-code-highlighting.d.ts +22 -0
  149. package/dist/hooks/use-code-highlighting.js +47 -0
  150. package/dist/hooks/use-is-truncated.d.ts +7 -0
  151. package/dist/hooks/use-is-truncated.js +23 -0
  152. package/dist/hooks/use-mobile.d.ts +2 -0
  153. package/dist/hooks/use-mobile.js +15 -0
  154. package/dist/icons/custom.d.ts +29 -0
  155. package/dist/icons/custom.js +48 -0
  156. package/dist/icons/index.d.ts +49 -0
  157. package/dist/icons/index.js +50 -0
  158. package/dist/icons/provider-logos.d.ts +17 -0
  159. package/dist/icons/provider-logos.js +28 -0
  160. package/dist/icons/providers.d.ts +9 -0
  161. package/dist/icons/providers.js +51 -0
  162. package/dist/index.d.ts +102 -0
  163. package/dist/index.js +124 -0
  164. package/dist/lib/code-highlighter.d.ts +9 -0
  165. package/dist/lib/code-highlighter.js +65 -0
  166. package/dist/lib/code-language.d.ts +13 -0
  167. package/dist/lib/code-language.js +103 -0
  168. package/dist/lib/code-tokens.d.ts +9 -0
  169. package/dist/lib/code-tokens.js +27 -0
  170. package/dist/lib/copy-text.d.ts +6 -0
  171. package/dist/lib/copy-text.js +46 -0
  172. package/dist/lib/home-tile.d.ts +12 -0
  173. package/dist/lib/home-tile.js +45 -0
  174. package/dist/lib/reveal-mask.d.ts +9 -0
  175. package/dist/lib/reveal-mask.js +16 -0
  176. package/dist/lib/text-direction.d.ts +28 -0
  177. package/dist/lib/text-direction.js +119 -0
  178. package/dist/lib/utils.d.ts +11 -0
  179. package/dist/lib/utils.js +30 -0
  180. package/dist/motion/components.d.ts +184 -0
  181. package/dist/motion/components.js +211 -0
  182. package/dist/motion/config.d.ts +849 -0
  183. package/dist/motion/config.js +429 -0
  184. package/dist/motion/index.d.ts +8 -0
  185. package/dist/motion/index.js +8 -0
  186. package/dist/motion/modal-presence.d.ts +5 -0
  187. package/dist/motion/modal-presence.js +27 -0
  188. package/dist/motion/popup.d.ts +77 -0
  189. package/dist/motion/popup.js +103 -0
  190. package/dist/platform/index.d.ts +29 -0
  191. package/dist/platform/index.js +63 -0
  192. package/dist/styles/base.css +319 -0
  193. package/dist/styles/fonts/Figtree-Variable.woff2 +0 -0
  194. package/dist/styles/fonts/OFL.txt +93 -0
  195. package/dist/styles/fonts/Poppins-Medium.woff2 +0 -0
  196. package/dist/styles/fonts/Poppins-Regular.woff2 +0 -0
  197. package/dist/styles/fonts/Poppins-SemiBold.woff2 +0 -0
  198. package/dist/styles/fonts.css +28 -0
  199. package/dist/styles/globals.css +8 -0
  200. package/dist/styles/mcp-host.css +76 -0
  201. package/dist/styles/tokens.css +387 -0
  202. package/dist/styles/tokens.d.mts +57 -0
  203. package/dist/styles/tokens.mjs +59 -0
  204. package/dist/theme/index.d.ts +28 -0
  205. package/dist/theme/index.js +65 -0
  206. package/package.json +136 -3
@@ -0,0 +1,447 @@
1
+ import * as React from 'react';
2
+ import type { LexicalCommand, SerializedEditorState, SerializedLexicalNode } from 'lexical';
3
+ import { type NodeKey, type EditorConfig, DecoratorNode } from 'lexical';
4
+ import { type AgentPicture } from './agent-avatar.js';
5
+ import { type ProviderMarkType } from '../../icons/index.js';
6
+ /** Person/agent row for the `@` typeahead. */
7
+ export type UserMentionCandidate = {
8
+ userId: string;
9
+ displayName: string;
10
+ avatarUrl?: string | null;
11
+ /** Distinguishes humans from agents in the picker (agent rows use a bot glyph). */
12
+ kind?: 'human' | 'agent';
13
+ /** An agent's Pingo or other resolved picture; wins over `avatarUrl` for agent rows. */
14
+ agentPicture?: AgentPicture | null;
15
+ /** The provider mark (and its accessible name) hung on an agent row's picture. */
16
+ providerBadge?: {
17
+ type: ProviderMarkType;
18
+ label: string;
19
+ } | null;
20
+ /** An agent's role, shown muted after its name. Humans carry none. */
21
+ role?: string | null;
22
+ /**
23
+ * When true the row stays visible but cannot be inserted (e.g. interactPolicy owner_only).
24
+ * Hosts set `disabledReason` for the muted subtitle.
25
+ */
26
+ disabled?: boolean;
27
+ /** Shown under the name when `disabled` (e.g. “Only Ada can interact with this agent”). */
28
+ disabledReason?: string;
29
+ /**
30
+ * Muted line under the name when the row is selectable (e.g. “Not in this stream”).
31
+ * Ignored when `disabled` — `disabledReason` wins.
32
+ */
33
+ subtitle?: string;
34
+ };
35
+ /**
36
+ * Synthetic `@all` row — everyone (human) in the current stream. Discriminated so hosts never
37
+ * invent a fake `userId` sentinel.
38
+ */
39
+ export type AllMentionCandidate = {
40
+ kind: 'all';
41
+ displayName: string;
42
+ subtitle?: string;
43
+ };
44
+ export type MentionCandidate = UserMentionCandidate | AllMentionCandidate;
45
+ export declare const isAllMentionCandidate: (candidate: MentionCandidate) => candidate is AllMentionCandidate;
46
+ /** Page request for the `@` typeahead. `offset` counts user rows only (not `@all`). */
47
+ export type MentionSearchOptions = {
48
+ offset: number;
49
+ limit: number;
50
+ };
51
+ /** One page of `@` candidates. Hosts set `hasMore` when further pages exist. */
52
+ export type MentionSearchResult = {
53
+ items: MentionCandidate[];
54
+ hasMore: boolean;
55
+ /**
56
+ * The complete first page from the slower source (the server), replacing `items` when it
57
+ * arrives. `items` are what the host holds locally and show at once. Only meaningful on the first
58
+ * page (`offset` 0). A rejection keeps `items`.
59
+ */
60
+ refresh?: Promise<MentionSearchResult>;
61
+ };
62
+ /** Default page size for the mention picker (first paint + each scroll fetch). */
63
+ export declare const MENTION_PAGE_SIZE = 10;
64
+ /** Host-supplied slash command for the composer typeahead (cycle triggers today). */
65
+ export type SlashCommandCandidate = {
66
+ /** Host identity when `name` is not unique (two streams can have the same cycle name). */
67
+ key?: string;
68
+ name: string;
69
+ description: string;
70
+ /** Inserts a `CycleTriggerNode` via the same path as host `insertCycleTrigger`. */
71
+ cycleTriggerName?: string;
72
+ /** Plain insert when `cycleTriggerName` is absent; `null` means no text insert. */
73
+ insertText?: string | null;
74
+ /** Menu section; the menu lists `cycles` before `commands`. Ungrouped candidates show under one title. */
75
+ group?: 'cycles' | 'commands';
76
+ /** Draws a soft sweeping highlight behind the row, to point a first-time user at it. */
77
+ emphasis?: boolean;
78
+ };
79
+ /** Host-supplied emoji for the `:` shortcode typeahead (Slack-style `:smile:`). */
80
+ export type EmojiCandidate = {
81
+ /** Native emoji glyph inserted into the message (empty for account custom emoji). */
82
+ char: string;
83
+ /** Shortcode without colons (e.g. `smile`, `+1`). */
84
+ shortcode: string;
85
+ /** Optional display name shown beside the shortcode. */
86
+ name?: string;
87
+ /** When set, selecting inserts a `CustomEmojiNode` (image) instead of `char`. */
88
+ imageUrl?: string;
89
+ };
90
+ /**
91
+ * One emoji the person chose from the `:` menu or typed as a complete `:shortcode:`, reported once
92
+ * after it is in the document. Paste, drop, undo/redo, draft restore and programmatic inserts
93
+ * never report.
94
+ */
95
+ export type EmojiUse = {
96
+ source: 'typeahead' | 'typed_shortcode';
97
+ kind: 'unicode' | 'custom';
98
+ /** The native glyph, or the shortcode name of a custom emoji (the host resolves aliases). */
99
+ emoji: string;
100
+ };
101
+ /** Default page size for the emoji shortcode typeahead. */
102
+ export declare const EMOJI_TYPEAHEAD_LIMIT = 24;
103
+ /** Host-supplied stream for the `#` typeahead; chips display as `~title`. */
104
+ export type StreamCandidate = {
105
+ streamId: string;
106
+ title: string;
107
+ /** Drives the private lock affordance in the typeahead and inserted chip. */
108
+ visibility: 'public' | 'private';
109
+ };
110
+ /** Default page size for the stream chip typeahead. */
111
+ export declare const STREAM_TYPEAHEAD_LIMIT = 10;
112
+ interface MentionNodePayload {
113
+ userId?: string;
114
+ displayName?: string;
115
+ all?: boolean;
116
+ }
117
+ /** Custom node that round-trips with contracts/chat/adapters/lexical.ts */
118
+ export declare class MentionNode extends DecoratorNode<React.JSX.Element> {
119
+ __userId: string | undefined;
120
+ __displayName: string | undefined;
121
+ __all: boolean | undefined;
122
+ static getType(): string;
123
+ static clone(node: MentionNode): MentionNode;
124
+ constructor(payload: MentionNodePayload, key?: NodeKey);
125
+ createDOM(_config: EditorConfig): HTMLElement;
126
+ updateDOM(): false;
127
+ static importJSON(serialized: any): MentionNode;
128
+ exportJSON(): SerializedLexicalNode & MentionNodePayload;
129
+ decorate(): React.JSX.Element;
130
+ isInline(): boolean;
131
+ }
132
+ export declare const $isMentionNode: (node: unknown) => node is MentionNode;
133
+ interface CycleTriggerNodePayload {
134
+ triggerName: string;
135
+ }
136
+ /** Custom node that round-trips with contracts/chat/adapters/lexical.ts */
137
+ export declare class CycleTriggerNode extends DecoratorNode<React.JSX.Element> {
138
+ __triggerName: string;
139
+ static getType(): string;
140
+ static clone(node: CycleTriggerNode): CycleTriggerNode;
141
+ constructor(payload: CycleTriggerNodePayload, key?: NodeKey);
142
+ createDOM(_config: EditorConfig): HTMLElement;
143
+ updateDOM(): false;
144
+ static importJSON(serialized: any): CycleTriggerNode;
145
+ exportJSON(): SerializedLexicalNode & CycleTriggerNodePayload;
146
+ decorate(): React.JSX.Element;
147
+ isInline(): boolean;
148
+ }
149
+ export declare const $createCycleTriggerNode: (triggerName: string) => CycleTriggerNode;
150
+ export declare const $isCycleTriggerNode: (node: unknown) => node is CycleTriggerNode;
151
+ interface StreamChipNodePayload {
152
+ streamId: string;
153
+ title: string;
154
+ visibility?: 'public' | 'private';
155
+ }
156
+ /** Custom node that round-trips with contracts/chat/adapters/lexical.ts (`type: 'stream-chip'`). */
157
+ export declare class StreamChipNode extends DecoratorNode<React.JSX.Element> {
158
+ __streamId: string;
159
+ __title: string;
160
+ __visibility?: 'public' | 'private';
161
+ static getType(): string;
162
+ static clone(node: StreamChipNode): StreamChipNode;
163
+ constructor(payload: StreamChipNodePayload, key?: NodeKey);
164
+ createDOM(_config: EditorConfig): HTMLElement;
165
+ updateDOM(): false;
166
+ static importJSON(serialized: any): StreamChipNode;
167
+ exportJSON(): SerializedLexicalNode & StreamChipNodePayload;
168
+ decorate(): React.JSX.Element;
169
+ isInline(): boolean;
170
+ }
171
+ export declare const $createStreamChipNode: (streamId: string, title: string, visibility?: "public" | "private") => StreamChipNode;
172
+ export declare const $isStreamChipNode: (node: unknown) => node is StreamChipNode;
173
+ interface CustomEmojiNodePayload {
174
+ name: string;
175
+ imageUrl: string;
176
+ }
177
+ /**
178
+ * Account custom emoji in the composer — renders the image; serializes as `custom-emoji` and the
179
+ * lexical adapter stores `:name:` text in MessageContent.
180
+ */
181
+ export declare class CustomEmojiNode extends DecoratorNode<React.JSX.Element> {
182
+ __name: string;
183
+ __imageUrl: string;
184
+ static getType(): string;
185
+ static clone(node: CustomEmojiNode): CustomEmojiNode;
186
+ constructor(payload: CustomEmojiNodePayload, key?: NodeKey);
187
+ createDOM(_config: EditorConfig): HTMLElement;
188
+ updateDOM(): false;
189
+ static importJSON(serialized: any): CustomEmojiNode;
190
+ exportJSON(): SerializedLexicalNode & CustomEmojiNodePayload;
191
+ decorate(): React.JSX.Element;
192
+ isInline(): boolean;
193
+ getTextContent(): string;
194
+ }
195
+ export declare const $createCustomEmojiNode: (name: string, imageUrl: string) => CustomEmojiNode;
196
+ export declare const $isCustomEmojiNode: (node: unknown) => node is CustomEmojiNode;
197
+ /**
198
+ * Replaces the `/query` text at the start of the first paragraph with a `CycleTriggerNode` and a
199
+ * space. Refused (no-op) while the editor already holds a trigger: one `/trigger` per message.
200
+ */
201
+ export declare const INSERT_CYCLE_TRIGGER_COMMAND: LexicalCommand<{
202
+ triggerName: string;
203
+ /** Swap an existing trigger for this one instead of refusing. */
204
+ replace?: boolean;
205
+ }>;
206
+ /** Inserts a `CustomEmojiNode` at the caret (picker / host-driven). */
207
+ export declare const INSERT_CUSTOM_EMOJI_COMMAND: LexicalCommand<{
208
+ name: string;
209
+ imageUrl: string;
210
+ }>;
211
+ export type CycleTriggerRequest = {
212
+ triggerName: string;
213
+ /** Swap the trigger already in the message (a picker choosing another cycle). */
214
+ replace?: boolean;
215
+ /** Changes on every request so the same trigger can be inserted again after a clear. */
216
+ nonce: number;
217
+ };
218
+ export type CustomEmojiRequest = {
219
+ name: string;
220
+ imageUrl: string;
221
+ /** Changes on every request so the same emoji can be inserted again. */
222
+ nonce: number;
223
+ };
224
+ /** Closing-colon expand may return a native glyph or a custom emoji image. */
225
+ export type EmojiShortcodeResolve = string | {
226
+ name: string;
227
+ imageUrl: string;
228
+ };
229
+ /** Host-driven text insertion at the caret (composer `@` / `/` buttons). */
230
+ export type InsertTextRequest = {
231
+ text: string;
232
+ /** Changes on every request so the same text can be inserted again. */
233
+ nonce: number;
234
+ };
235
+ /**
236
+ * The part of the layout viewport the user sees, in layout-viewport Y (the menu is `position:
237
+ * fixed`, so everything here shares the coordinates of `getBoundingClientRect`). The visual
238
+ * viewport is a window into the layout viewport, so it can neither start below nor end past it.
239
+ * Inside the iOS app `offsetTop` has been seen to stay at the keyboard pan after the page was
240
+ * resized to sit above the keyboard: taken as is, it moved the top limit below the composer and
241
+ * left the list two rows tall. The clamp makes that report harmless.
242
+ */
243
+ export declare function visibleArea({ layoutHeight, offsetTop, height, }: {
244
+ layoutHeight: number;
245
+ offsetTop?: number;
246
+ height?: number;
247
+ }): {
248
+ topY: number;
249
+ bottomY: number;
250
+ };
251
+ /**
252
+ * Where the list's bottom edge goes and how tall it may be, in layout-viewport Y. The list sits
253
+ * above `preferredBottomY` (the composer footer top, or the caret line without a footer) and below
254
+ * the chrome, and never leaves `[visibleTopY, visibleBottomY]`. Its height is the room between
255
+ * them, up to 240px; a cramped screen shows fewer rows rather than rows under the native bar.
256
+ * Only a mobile composer footer (`coverDraftWhenCramped`) has a last resort: when under one row
257
+ * fits above the composer (landscape with the keyboard up), the list takes the top of the safe
258
+ * area and covers the draft, because a list nobody can reach is worse. Without a footer (desktop,
259
+ * inline edit) the bottom edge stays on the caret line so the typed text is never covered.
260
+ */
261
+ export declare function placeTypeahead({ preferredBottomY, visibleTopY, visibleBottomY, topChromePx: chromePx, coverDraftWhenCramped, }: {
262
+ /** Bottom edge that keeps the list clear of the composer (footer top or caret line). */
263
+ preferredBottomY: number;
264
+ visibleTopY: number;
265
+ visibleBottomY: number;
266
+ /** Safe-area inset plus the native bar; 0 when the page has none. */
267
+ topChromePx: number;
268
+ coverDraftWhenCramped?: boolean;
269
+ }): {
270
+ bottomY: number;
271
+ maxHeight: number;
272
+ };
273
+ /** Accessible names for the document-mode controls; English defaults, override for i18n. */
274
+ export type DocumentModeLabels = {
275
+ heading2: string;
276
+ heading3: string;
277
+ image: string;
278
+ imageAlt: string;
279
+ imageAltPlaceholder: string;
280
+ imageAltRequired: string;
281
+ imageRemove: string;
282
+ imageUnavailable: string;
283
+ uploading: string;
284
+ };
285
+ export type DocumentImageReject = 'type' | 'limit';
286
+ /**
287
+ * Opts the editor into document mode (the stream About): heading buttons, block images, a
288
+ * markdown shortcut set without code fences or strikethrough. Uploading stays with the host.
289
+ */
290
+ export type DocumentModeOptions = {
291
+ /** Content types the picker, paste and drop accept; anything else goes to `onReject`. */
292
+ acceptedImageTypes: readonly string[];
293
+ /** Stores one picked, pasted or dropped file; resolve to the asset id, or null when it failed (the host reports it). */
294
+ uploadImage: (file: File) => Promise<string | null>;
295
+ /** Preview URL for an image block; null while it is still being resolved. */
296
+ resolveImageUrl: (assetId: string) => string | null;
297
+ /** Most images the document may hold; further files go to `onReject('limit')`. */
298
+ maxImages?: number;
299
+ onReject?: (file: File, reason: DocumentImageReject) => void;
300
+ onUploadingChange?: (uploading: boolean) => void;
301
+ labels?: Partial<DocumentModeLabels>;
302
+ };
303
+ /** Block image that round-trips with contracts/streams/about-lexical.ts (`type: 'about-image'`). */
304
+ export declare class DocumentImageNode extends DecoratorNode<React.JSX.Element> {
305
+ __assetId: string;
306
+ __alt: string;
307
+ static getType(): string;
308
+ static clone(node: DocumentImageNode): DocumentImageNode;
309
+ constructor(assetId: string, alt: string, key?: NodeKey);
310
+ createDOM(_config: EditorConfig): HTMLElement;
311
+ updateDOM(): false;
312
+ static importJSON(serialized: any): DocumentImageNode;
313
+ exportJSON(): SerializedLexicalNode & {
314
+ assetId: string;
315
+ alt: string;
316
+ };
317
+ getAssetId(): string;
318
+ getAlt(): string;
319
+ setAlt(alt: string): this;
320
+ isInline(): boolean;
321
+ decorate(): React.JSX.Element;
322
+ }
323
+ export declare const $isDocumentImageNode: (node: unknown) => node is DocumentImageNode;
324
+ export type RichTextEditorLabels = {
325
+ toolbar: string;
326
+ bold: string;
327
+ italic: string;
328
+ strikethrough: string;
329
+ code: string;
330
+ bulletList: string;
331
+ numberedList: string;
332
+ link: string;
333
+ linkDialogTitle: string;
334
+ linkDialogDescription: string;
335
+ linkUrl: string;
336
+ linkUrlPlaceholder: string;
337
+ linkText: string;
338
+ linkTextPlaceholder: string;
339
+ linkInvalid: string;
340
+ linkRemove: string;
341
+ linkInsert: string;
342
+ cancel: string;
343
+ slashTitle: string;
344
+ slashEmpty: string;
345
+ slashCyclesTitle: string;
346
+ slashCommandsTitle: string;
347
+ emojiEmpty: string;
348
+ streamEmpty: string;
349
+ streamPrivate: string;
350
+ streamPublic: string;
351
+ /** What a chip reads while its stream's name is unknown (`~stream`). */
352
+ streamFallback: string;
353
+ };
354
+ /** Test-only: reset module-scoped remembered direction between cases. */
355
+ declare function __resetLastRememberedDirectionForTests(): void;
356
+ export type RichTextEditorProps = {
357
+ /** Serialized Lexical state; `null` for empty. Controlled. */
358
+ value: SerializedEditorState | null;
359
+ onChange: (state: SerializedEditorState) => void;
360
+ placeholder?: string;
361
+ /** Called with the text after `@`; return a page of candidates for the popover. */
362
+ searchMentions?: (query: string, options: MentionSearchOptions) => Promise<MentionSearchResult>;
363
+ /**
364
+ * Fires after a mention is inserted from the typeahead (not for disabled rows).
365
+ * Hosts use this for analytics (e.g. selecting a "Not in this stream" person).
366
+ */
367
+ onMentionSelect?: (candidate: MentionCandidate) => void;
368
+ /**
369
+ * Leading `/query` typeahead (cycle triggers). Host filters; return sync or Promise.
370
+ * Mounts the slash plugin when provided (pass a function that returns `[]` for the empty state).
371
+ */
372
+ searchSlashCommands?: (query: string) => SlashCommandCandidate[] | Promise<SlashCommandCandidate[]>;
373
+ /** Fires when a row of the slash menu is chosen, before the editor inserts it. */
374
+ onSlashCommandSelect?: (candidate: SlashCommandCandidate) => void;
375
+ /**
376
+ * A leading `/` (or `/query`, e.g. pasted) arrived. The editor removes that text and skips the
377
+ * inline menu, receiving the query so the host can open its own picker with it prefilled. Needs
378
+ * `searchSlashCommands` (the plugin mounts with it).
379
+ */
380
+ onSlashTyped?: (query: string) => void;
381
+ /**
382
+ * `:` shortcode typeahead (Slack-style `:smile:`). Host filters; return sync or Promise.
383
+ * Mounts the emoji plugin when provided.
384
+ */
385
+ searchEmojis?: (query: string) => EmojiCandidate[] | Promise<EmojiCandidate[]>;
386
+ /**
387
+ * Resolve a completed `:shortcode:` (closing colon typed) to a native glyph or custom emoji.
388
+ * When set with `searchEmojis`, typing `:thumbsup:` / `:ship-it:` expands without a menu pick.
389
+ */
390
+ resolveEmojiShortcode?: (shortcode: string) => EmojiShortcodeResolve | undefined;
391
+ /**
392
+ * Called once when an emoji enters the document by a menu pick or a typed complete `:shortcode:`
393
+ * (see `EmojiUse`). The editor makes no network calls itself; the host decides what to do.
394
+ */
395
+ onEmojiUsed?: (use: EmojiUse) => void;
396
+ /**
397
+ * `#` stream chip typeahead (Slack-style channel chips). Host filters; return sync or Promise.
398
+ * Mounts the stream plugin when provided.
399
+ */
400
+ searchStreams?: (query: string) => StreamCandidate[] | Promise<StreamCandidate[]>;
401
+ /** Called when the user presses Enter without Shift (and `sendOnEnter` is not `false`). */
402
+ onSubmit?: () => void;
403
+ /** Plain Enter submits when true (default). When false, plain Enter behaves like Shift+Enter (new line/list item) — for mobile, where only the send button submits. */
404
+ sendOnEnter?: boolean;
405
+ /** Host-driven `/trigger` insertion; dispatched once per `nonce` through `INSERT_CYCLE_TRIGGER_COMMAND`. */
406
+ insertCycleTrigger?: CycleTriggerRequest | null;
407
+ /** Host-driven custom emoji insertion; dispatched once per `nonce` through `INSERT_CUSTOM_EMOJI_COMMAND`. */
408
+ insertCustomEmoji?: CustomEmojiRequest | null;
409
+ /** Names (no slash) of plain-text commands whose leading `/name` is painted as a chip. */
410
+ chipSlashCommands?: readonly string[];
411
+ /** Why a `/trigger` chip cannot run, or null; a non-null answer adds an error icon with it on hover. */
412
+ cycleTriggerIssue?: (triggerName: string) => string | null;
413
+ onCycleTriggerInserted?: (nonce: number) => void;
414
+ onCustomEmojiInserted?: (nonce: number) => void;
415
+ /** Host-driven text insertion at the caret (composer `@` / `/` buttons). */
416
+ insertTextAtCaret?: InsertTextRequest | null;
417
+ /** Clear `insertTextAtCaret` after apply so a later editor remount (e.g. send) cannot re-insert it. */
418
+ onInsertTextAtCaret?: (nonce: number) => void;
419
+ disabled?: boolean;
420
+ /** Focus the editor, caret at the end, when it mounts. */
421
+ autoFocus?: boolean;
422
+ /** Show the formatting toolbar above the editable area. Defaults to `true`. */
423
+ toolbar?: boolean;
424
+ /**
425
+ * When true (default), stamp paragraph/list direction with word-vote detection
426
+ * (HAC DirectionPlugin). Set false to leave Lexical native / no explicit dir
427
+ * (Labs `chat_rtl_support` kill switch).
428
+ */
429
+ detectContentDirection?: boolean;
430
+ /** Accessible names and dialog copy; English defaults, override for i18n. */
431
+ labels?: Partial<RichTextEditorLabels>;
432
+ /** Opts into the document flavour (headings, block images, no strikethrough or code fences). */
433
+ documentMode?: DocumentModeOptions;
434
+ 'aria-label': string;
435
+ className?: string;
436
+ };
437
+ /**
438
+ * Controlled rich-text editor built on Lexical.
439
+ *
440
+ * Registered nodes: `HeadingNode`, `QuoteNode`, `ListNode`, `ListItemNode`,
441
+ * `LinkNode`, `AutoLinkNode`, `CodeNode`, `MentionNode` (`type: 'mention'`),
442
+ * `CycleTriggerNode` (`type: 'cycle-trigger'`), `StreamChipNode` (`type: 'stream-chip'`),
443
+ * `CustomEmojiNode` (`type: 'custom-emoji'`), `DocumentImageNode` (`type: 'about-image'`) — compatible with the
444
+ * `contracts/chat/adapters/lexical.ts` round-trip contract.
445
+ */
446
+ declare function RichTextEditor(props: RichTextEditorProps): React.JSX.Element;
447
+ export { RichTextEditor, __resetLastRememberedDirectionForTests };