@agent-native/toolkit 0.6.0 → 0.8.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 (174) hide show
  1. package/README.md +17 -1
  2. package/agent-native.eject.json +411 -0
  3. package/dist/chat-history/ChatHistoryList.d.ts +103 -0
  4. package/dist/chat-history/ChatHistoryList.d.ts.map +1 -0
  5. package/dist/chat-history/ChatHistoryList.js +109 -0
  6. package/dist/chat-history/ChatHistoryList.js.map +1 -0
  7. package/dist/chat-history/ChatHistoryList.spec.d.ts +2 -0
  8. package/dist/chat-history/ChatHistoryList.spec.d.ts.map +1 -0
  9. package/dist/chat-history/ChatHistoryList.spec.js +283 -0
  10. package/dist/chat-history/ChatHistoryList.spec.js.map +1 -0
  11. package/dist/chat-history/index.d.ts +2 -0
  12. package/dist/chat-history/index.d.ts.map +1 -0
  13. package/dist/chat-history/index.js +2 -0
  14. package/dist/chat-history/index.js.map +1 -0
  15. package/dist/chat-history.css +314 -0
  16. package/package.json +20 -1
  17. package/src/app-shell/header-actions.tsx +84 -0
  18. package/src/app-shell/index.ts +1 -0
  19. package/src/chat-history/ChatHistoryList.spec.tsx +453 -0
  20. package/src/chat-history/ChatHistoryList.tsx +469 -0
  21. package/src/chat-history/index.ts +7 -0
  22. package/src/chat-history.css +314 -0
  23. package/src/collab-ui/AgentPresenceChip.tsx +69 -0
  24. package/src/collab-ui/LiveCursorOverlay.tsx +241 -0
  25. package/src/collab-ui/PresenceBar.tsx +346 -0
  26. package/src/collab-ui/RecentEditHighlights.tsx +225 -0
  27. package/src/collab-ui/RemoteSelectionRings.tsx +227 -0
  28. package/src/collab-ui/agent-identity.ts +16 -0
  29. package/src/collab-ui/index.ts +39 -0
  30. package/src/collab-ui/lead-client.ts +32 -0
  31. package/src/collab-ui/types.spec.ts +18 -0
  32. package/src/collab-ui/types.ts +96 -0
  33. package/src/composer/AgentComposerFrame.tsx +59 -0
  34. package/src/composer/ComposerPlusMenu.tsx +983 -0
  35. package/src/composer/MentionPopover.tsx +412 -0
  36. package/src/composer/PastedTextChip.tsx +150 -0
  37. package/src/composer/PromptComposer.spec.ts +73 -0
  38. package/src/composer/PromptComposer.tsx +718 -0
  39. package/src/composer/RealtimeVoiceMode.spec.tsx +771 -0
  40. package/src/composer/RealtimeVoiceMode.tsx +856 -0
  41. package/src/composer/TiptapComposer.spec.ts +390 -0
  42. package/src/composer/TiptapComposer.tsx +2936 -0
  43. package/src/composer/VoiceButton.spec.ts +33 -0
  44. package/src/composer/VoiceButton.tsx +255 -0
  45. package/src/composer/asset-picker-url.spec.ts +56 -0
  46. package/src/composer/asset-picker-url.ts +80 -0
  47. package/src/composer/attachment-accept.spec.ts +22 -0
  48. package/src/composer/attachment-accept.ts +71 -0
  49. package/src/composer/draft-key.spec.ts +19 -0
  50. package/src/composer/draft-key.ts +7 -0
  51. package/src/composer/extensions/FileReference.tsx +55 -0
  52. package/src/composer/extensions/MentionReference.tsx +93 -0
  53. package/src/composer/extensions/SkillReference.tsx +56 -0
  54. package/src/composer/index.ts +79 -0
  55. package/src/composer/pasted-text.spec.ts +162 -0
  56. package/src/composer/pasted-text.ts +160 -0
  57. package/src/composer/prompt-attachments.spec.ts +80 -0
  58. package/src/composer/prompt-attachments.ts +93 -0
  59. package/src/composer/realtime-voice-audio-level.spec.ts +32 -0
  60. package/src/composer/realtime-voice-audio-level.ts +64 -0
  61. package/src/composer/realtime-voice-transcript.spec.ts +95 -0
  62. package/src/composer/realtime-voice-transcript.ts +134 -0
  63. package/src/composer/runtime-adapters.tsx +343 -0
  64. package/src/composer/types.ts +66 -0
  65. package/src/composer/use-file-search.ts +64 -0
  66. package/src/composer/use-mention-search.ts +90 -0
  67. package/src/composer/use-skills.ts +45 -0
  68. package/src/composer/useRealtimeVoiceMode.spec.ts +818 -0
  69. package/src/composer/useRealtimeVoiceMode.tsx +2117 -0
  70. package/src/composer/useVoiceDictation.spec.ts +45 -0
  71. package/src/composer/useVoiceDictation.ts +1191 -0
  72. package/src/context-ui/ContextMeter.tsx +101 -0
  73. package/src/context-ui/ContextSegmentRow.tsx +184 -0
  74. package/src/context-ui/ContextTreemap.tsx +125 -0
  75. package/src/context-ui/ContextXRayPanel.tsx +377 -0
  76. package/src/context-ui/format.ts +42 -0
  77. package/src/context-ui/index.ts +15 -0
  78. package/src/context-ui/types.ts +43 -0
  79. package/src/design-tweaks/index.ts +1 -0
  80. package/src/design-tweaks/visual-style-controls.tsx +1084 -0
  81. package/src/editor/BubbleToolbar.tsx +253 -0
  82. package/src/editor/CodeBlockNode.tsx +254 -0
  83. package/src/editor/DragHandle.spec.ts +588 -0
  84. package/src/editor/DragHandle.ts +1437 -0
  85. package/src/editor/ImageExtension.roundtrip.spec.ts +117 -0
  86. package/src/editor/ImageExtension.ts +306 -0
  87. package/src/editor/RegistryBlockContext.tsx +107 -0
  88. package/src/editor/RegistryBlockNode.spec.ts +279 -0
  89. package/src/editor/RegistryBlockNode.tsx +652 -0
  90. package/src/editor/RichMarkdownEditor.collab.spec.ts +79 -0
  91. package/src/editor/RichMarkdownEditor.roundtrip.spec.ts +226 -0
  92. package/src/editor/RichMarkdownEditor.tsx +81 -0
  93. package/src/editor/RunId.ts +61 -0
  94. package/src/editor/SharedRichEditor.tsx +321 -0
  95. package/src/editor/SlashCommandMenu.tsx +310 -0
  96. package/src/editor/disableHistory.spec.ts +85 -0
  97. package/src/editor/extensions.ts +402 -0
  98. package/src/editor/gfmDoc.spec.ts +230 -0
  99. package/src/editor/gfmDoc.ts +92 -0
  100. package/src/editor/index.ts +93 -0
  101. package/src/editor/registrySlashCommands.ts +131 -0
  102. package/src/editor/structuralReorderUndo.spec.ts +144 -0
  103. package/src/editor/surgical-apply.spec.ts +279 -0
  104. package/src/editor/surgical-apply.ts +192 -0
  105. package/src/editor/useCollabReconcile.concurrent.spec.ts +422 -0
  106. package/src/editor/useCollabReconcile.idempotent.spec.ts +324 -0
  107. package/src/editor/useCollabReconcile.ts +589 -0
  108. package/src/editor.css +510 -0
  109. package/src/hooks/index.ts +2 -0
  110. package/src/hooks/use-mobile.tsx +21 -0
  111. package/src/hooks/use-toast.ts +188 -0
  112. package/src/index.ts +8 -0
  113. package/src/onboarding/index.ts +1 -0
  114. package/src/provider.tsx +47 -0
  115. package/src/sharing/VisibilityBadge.spec.ts +96 -0
  116. package/src/sharing/VisibilityBadge.tsx +37 -0
  117. package/src/sharing/index.ts +4 -0
  118. package/src/styles.css +21 -0
  119. package/src/ui/accordion.tsx +56 -0
  120. package/src/ui/alert-dialog.tsx +141 -0
  121. package/src/ui/alert.tsx +59 -0
  122. package/src/ui/aspect-ratio.tsx +5 -0
  123. package/src/ui/avatar.tsx +48 -0
  124. package/src/ui/badge.tsx +37 -0
  125. package/src/ui/breadcrumb.tsx +115 -0
  126. package/src/ui/button.tsx +78 -0
  127. package/src/ui/calendar.tsx +214 -0
  128. package/src/ui/card.tsx +86 -0
  129. package/src/ui/carousel.tsx +260 -0
  130. package/src/ui/chart.tsx +375 -0
  131. package/src/ui/checkbox.tsx +28 -0
  132. package/src/ui/collapsible.tsx +9 -0
  133. package/src/ui/command.spec.tsx +51 -0
  134. package/src/ui/command.tsx +174 -0
  135. package/src/ui/context-menu.tsx +202 -0
  136. package/src/ui/date-picker.tsx +64 -0
  137. package/src/ui/dialog.spec.tsx +43 -0
  138. package/src/ui/dialog.tsx +146 -0
  139. package/src/ui/drawer.tsx +126 -0
  140. package/src/ui/dropdown-menu.tsx +218 -0
  141. package/src/ui/form.tsx +177 -0
  142. package/src/ui/hover-card.tsx +27 -0
  143. package/src/ui/index.ts +52 -0
  144. package/src/ui/input-otp.tsx +69 -0
  145. package/src/ui/input.tsx +22 -0
  146. package/src/ui/label.tsx +24 -0
  147. package/src/ui/logo.tsx +36 -0
  148. package/src/ui/menubar.tsx +235 -0
  149. package/src/ui/navigation-menu.tsx +128 -0
  150. package/src/ui/pagination.tsx +121 -0
  151. package/src/ui/popover.tsx +44 -0
  152. package/src/ui/progress.tsx +26 -0
  153. package/src/ui/radio-group.tsx +42 -0
  154. package/src/ui/resizable.tsx +43 -0
  155. package/src/ui/scroll-area.tsx +46 -0
  156. package/src/ui/select.tsx +158 -0
  157. package/src/ui/separator.tsx +29 -0
  158. package/src/ui/sheet.tsx +160 -0
  159. package/src/ui/sidebar.tsx +777 -0
  160. package/src/ui/skeleton.tsx +18 -0
  161. package/src/ui/slider.tsx +26 -0
  162. package/src/ui/sonner.tsx +58 -0
  163. package/src/ui/spinner.tsx +17 -0
  164. package/src/ui/switch.tsx +27 -0
  165. package/src/ui/table.tsx +117 -0
  166. package/src/ui/tabs.tsx +53 -0
  167. package/src/ui/textarea.tsx +23 -0
  168. package/src/ui/toast.tsx +127 -0
  169. package/src/ui/toaster.tsx +33 -0
  170. package/src/ui/toggle-group.tsx +59 -0
  171. package/src/ui/toggle.tsx +43 -0
  172. package/src/ui/tooltip.tsx +53 -0
  173. package/src/ui/use-toast.ts +3 -0
  174. package/src/utils.ts +8 -0
package/src/editor.css ADDED
@@ -0,0 +1,510 @@
1
+ .an-rich-md-wrapper {
2
+ min-height: 100%;
3
+ position: relative;
4
+ cursor: text;
5
+ }
6
+
7
+ .an-rich-md-wrapper--readonly {
8
+ cursor: default;
9
+ }
10
+
11
+ .an-rich-md-loading {
12
+ min-height: 7rem;
13
+ }
14
+
15
+ .an-rich-md-prose {
16
+ outline: none;
17
+ color: hsl(var(--foreground));
18
+ line-height: 1.65;
19
+ font-size: 0.95rem;
20
+ min-height: 1.65em;
21
+ text-align: start;
22
+ }
23
+
24
+ .an-rich-md-prose > *:first-child {
25
+ margin-top: 0;
26
+ }
27
+
28
+ .an-rich-md-prose h1 {
29
+ font-size: 1.85em;
30
+ font-weight: 700;
31
+ margin: 1em 0 0.3em;
32
+ line-height: 1.18;
33
+ }
34
+
35
+ .an-rich-md-prose h2 {
36
+ font-size: 1.45em;
37
+ font-weight: 650;
38
+ margin: 0.9em 0 0.25em;
39
+ line-height: 1.25;
40
+ }
41
+
42
+ .an-rich-md-prose h3 {
43
+ font-size: 1.18em;
44
+ font-weight: 650;
45
+ margin: 0.75em 0 0.2em;
46
+ line-height: 1.32;
47
+ }
48
+
49
+ .an-rich-md-prose h4 {
50
+ font-size: 1em;
51
+ font-weight: 650;
52
+ margin: 0.65em 0 0.15em;
53
+ line-height: 1.35;
54
+ }
55
+
56
+ .an-rich-md-prose p {
57
+ margin: 0.45em 0;
58
+ min-height: 1.65em;
59
+ }
60
+
61
+ .an-rich-md-prose ul:not(.an-rich-md-task-list),
62
+ .an-rich-md-prose ol {
63
+ padding-inline-start: 1.45em;
64
+ margin: 0.35em 0;
65
+ }
66
+
67
+ .an-rich-md-prose ul:not(.an-rich-md-task-list) {
68
+ list-style-type: disc;
69
+ }
70
+
71
+ .an-rich-md-prose ol {
72
+ list-style-type: decimal;
73
+ }
74
+
75
+ .an-rich-md-prose li {
76
+ margin: 0.12em 0;
77
+ }
78
+
79
+ .an-rich-md-prose li p {
80
+ margin: 0;
81
+ }
82
+
83
+ .an-rich-md-task-list {
84
+ list-style: none;
85
+ margin: 0.35em 0;
86
+ padding-inline-start: 0;
87
+ }
88
+
89
+ .an-rich-md-task-list li {
90
+ display: flex;
91
+ align-items: flex-start;
92
+ gap: 0.45em;
93
+ margin: 0.18em 0;
94
+ }
95
+
96
+ .an-rich-md-task-list li label {
97
+ display: inline-flex;
98
+ align-items: center;
99
+ height: 1.65em;
100
+ }
101
+
102
+ .an-rich-md-task-list li input[type="checkbox"] {
103
+ width: 0.95em;
104
+ height: 0.95em;
105
+ accent-color: hsl(var(--primary));
106
+ }
107
+
108
+ .an-rich-md-task-list li > div {
109
+ flex: 1;
110
+ }
111
+
112
+ .an-rich-md-prose blockquote {
113
+ border-inline-start: 2px solid hsl(var(--border));
114
+ padding-inline-start: 0.9em;
115
+ margin: 0.45em 0;
116
+ color: hsl(var(--muted-foreground));
117
+ }
118
+
119
+ .an-rich-md-prose code {
120
+ unicode-bidi: isolate;
121
+ font-family:
122
+ ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
123
+ font-size: 0.88em;
124
+ background: hsl(var(--muted));
125
+ padding: 0.12em 0.32em;
126
+ border-radius: 4px;
127
+ }
128
+
129
+ .an-rich-md-prose :not(pre) > code {
130
+ direction: ltr;
131
+ }
132
+
133
+ .an-rich-md-prose pre {
134
+ font-family:
135
+ ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
136
+ font-size: 0.86em;
137
+ /* Theme-aware code surface: follows the app's muted/foreground/border tokens
138
+ so block code respects light and dark mode (the token palette below is
139
+ tuned to read on a muted surface in both). */
140
+ background: hsl(var(--muted));
141
+ color: hsl(var(--foreground));
142
+ border: 1px solid hsl(var(--border));
143
+ border-radius: 6px;
144
+ padding: 0.8em 1em;
145
+ margin: 0.55em 0;
146
+ overflow-x: auto;
147
+ line-height: 1.5;
148
+ }
149
+
150
+ .an-rich-md-prose pre code {
151
+ background: none;
152
+ border: none;
153
+ padding: 0;
154
+ font-size: inherit;
155
+ color: inherit;
156
+ }
157
+
158
+ /* highlight.js (lowlight) token palette. Scoped to block code so inline `code`
159
+ keeps its own background. No highlight.js base theme is imported; these rules
160
+ are the entire theme, tuned (mid-lightness HSL) to read on the muted surface
161
+ above in both light and dark mode. */
162
+ .an-rich-md-prose pre code .hljs-comment,
163
+ .an-rich-md-prose pre code .hljs-quote {
164
+ color: hsl(var(--muted-foreground));
165
+ font-style: italic;
166
+ }
167
+ .an-rich-md-prose pre code .hljs-keyword,
168
+ .an-rich-md-prose pre code .hljs-selector-tag,
169
+ .an-rich-md-prose pre code .hljs-literal,
170
+ .an-rich-md-prose pre code .hljs-doctag {
171
+ color: hsl(280 60% 58%);
172
+ }
173
+ .an-rich-md-prose pre code .hljs-string,
174
+ .an-rich-md-prose pre code .hljs-regexp,
175
+ .an-rich-md-prose pre code .hljs-addition {
176
+ color: hsl(140 52% 40%);
177
+ }
178
+ .an-rich-md-prose pre code .hljs-number,
179
+ .an-rich-md-prose pre code .hljs-symbol,
180
+ .an-rich-md-prose pre code .hljs-literal {
181
+ color: hsl(28 78% 48%);
182
+ }
183
+ .an-rich-md-prose pre code .hljs-meta {
184
+ color: hsl(var(--muted-foreground));
185
+ }
186
+ .an-rich-md-prose pre code .hljs-title,
187
+ .an-rich-md-prose pre code .hljs-title.function_,
188
+ .an-rich-md-prose pre code .hljs-section {
189
+ color: hsl(210 72% 52%);
190
+ }
191
+ .an-rich-md-prose pre code .hljs-built_in,
192
+ .an-rich-md-prose pre code .hljs-type,
193
+ .an-rich-md-prose pre code .hljs-title.class_,
194
+ .an-rich-md-prose pre code .hljs-variable.language_ {
195
+ color: hsl(190 64% 40%);
196
+ }
197
+ .an-rich-md-prose pre code .hljs-attr,
198
+ .an-rich-md-prose pre code .hljs-attribute,
199
+ .an-rich-md-prose pre code .hljs-property,
200
+ .an-rich-md-prose pre code .hljs-params {
201
+ color: hsl(35 68% 46%);
202
+ }
203
+ .an-rich-md-prose pre code .hljs-name,
204
+ .an-rich-md-prose pre code .hljs-tag,
205
+ .an-rich-md-prose pre code .hljs-selector-id,
206
+ .an-rich-md-prose pre code .hljs-selector-class {
207
+ color: hsl(350 62% 52%);
208
+ }
209
+ .an-rich-md-prose pre code .hljs-deletion {
210
+ color: hsl(0 62% 52%);
211
+ }
212
+ .an-rich-md-prose pre code .hljs-emphasis {
213
+ font-style: italic;
214
+ }
215
+ .an-rich-md-prose pre code .hljs-strong {
216
+ font-weight: 600;
217
+ }
218
+
219
+ /* In dark mode, lift the token lightness for contrast on the dark muted surface. */
220
+ .dark .an-rich-md-prose pre code .hljs-keyword,
221
+ .dark .an-rich-md-prose pre code .hljs-selector-tag,
222
+ .dark .an-rich-md-prose pre code .hljs-literal,
223
+ .dark .an-rich-md-prose pre code .hljs-doctag {
224
+ color: hsl(280 72% 72%);
225
+ }
226
+ .dark .an-rich-md-prose pre code .hljs-string,
227
+ .dark .an-rich-md-prose pre code .hljs-regexp,
228
+ .dark .an-rich-md-prose pre code .hljs-addition {
229
+ color: hsl(140 48% 62%);
230
+ }
231
+ .dark .an-rich-md-prose pre code .hljs-number,
232
+ .dark .an-rich-md-prose pre code .hljs-symbol,
233
+ .dark .an-rich-md-prose pre code .hljs-literal {
234
+ color: hsl(30 85% 65%);
235
+ }
236
+ .dark .an-rich-md-prose pre code .hljs-title,
237
+ .dark .an-rich-md-prose pre code .hljs-title.function_,
238
+ .dark .an-rich-md-prose pre code .hljs-section {
239
+ color: hsl(210 80% 70%);
240
+ }
241
+ .dark .an-rich-md-prose pre code .hljs-built_in,
242
+ .dark .an-rich-md-prose pre code .hljs-type,
243
+ .dark .an-rich-md-prose pre code .hljs-title.class_,
244
+ .dark .an-rich-md-prose pre code .hljs-variable.language_ {
245
+ color: hsl(190 70% 62%);
246
+ }
247
+ .dark .an-rich-md-prose pre code .hljs-attr,
248
+ .dark .an-rich-md-prose pre code .hljs-attribute,
249
+ .dark .an-rich-md-prose pre code .hljs-property,
250
+ .dark .an-rich-md-prose pre code .hljs-params {
251
+ color: hsl(40 78% 66%);
252
+ }
253
+ .dark .an-rich-md-prose pre code .hljs-name,
254
+ .dark .an-rich-md-prose pre code .hljs-tag,
255
+ .dark .an-rich-md-prose pre code .hljs-selector-id,
256
+ .dark .an-rich-md-prose pre code .hljs-selector-class {
257
+ color: hsl(350 72% 68%);
258
+ }
259
+
260
+ .an-rich-md-prose hr {
261
+ border: none;
262
+ border-top: 1px solid hsl(var(--border));
263
+ margin: 1.1em 0;
264
+ }
265
+
266
+ .an-rich-md-table {
267
+ width: 100%;
268
+ border-collapse: collapse;
269
+ margin: 0.7em 0;
270
+ table-layout: fixed;
271
+ }
272
+
273
+ .an-rich-md-table td,
274
+ .an-rich-md-table th {
275
+ border: 1px solid hsl(var(--border));
276
+ padding: 0.45em 0.55em;
277
+ vertical-align: top;
278
+ }
279
+
280
+ .an-rich-md-table th {
281
+ background: hsl(var(--muted) / 0.6);
282
+ font-weight: 650;
283
+ }
284
+
285
+ .an-rich-md-table p {
286
+ margin: 0;
287
+ }
288
+
289
+ .an-rich-md-prose strong {
290
+ font-weight: 650;
291
+ }
292
+
293
+ .an-rich-md-prose em {
294
+ font-style: italic;
295
+ }
296
+
297
+ .an-rich-md-prose s {
298
+ text-decoration: line-through;
299
+ }
300
+
301
+ .an-rich-md-link {
302
+ color: hsl(var(--foreground));
303
+ text-decoration: underline;
304
+ text-underline-offset: 2px;
305
+ text-decoration-color: hsl(var(--muted-foreground));
306
+ cursor: pointer;
307
+ }
308
+
309
+ .an-rich-md-link:hover {
310
+ text-decoration-color: hsl(var(--foreground));
311
+ }
312
+
313
+ .an-rich-md-prose p.is-editor-empty:first-child::before,
314
+ .an-rich-md-prose p.is-empty::before,
315
+ .an-rich-md-prose h1.is-empty::before,
316
+ .an-rich-md-prose h2.is-empty::before,
317
+ .an-rich-md-prose h3.is-empty::before,
318
+ .an-rich-md-prose h4.is-empty::before {
319
+ content: attr(data-placeholder);
320
+ float: inline-start;
321
+ color: hsl(var(--muted-foreground));
322
+ opacity: 0.55;
323
+ pointer-events: none;
324
+ height: 0;
325
+ }
326
+
327
+ .an-rich-md-prose ::selection {
328
+ background: hsl(var(--ring) / 0.22);
329
+ }
330
+
331
+ .an-rich-md-bubble-toolbar {
332
+ z-index: 9999;
333
+ display: flex;
334
+ align-items: center;
335
+ border-radius: 6px;
336
+ background: hsl(var(--popover));
337
+ color: hsl(var(--popover-foreground));
338
+ padding: 3px;
339
+ box-shadow:
340
+ 0 4px 16px rgb(0 0 0 / 0.25),
341
+ 0 0 0 1px hsl(var(--border));
342
+ }
343
+
344
+ .an-rich-md-bubble-items,
345
+ .an-rich-md-link-editor {
346
+ display: flex;
347
+ align-items: center;
348
+ gap: 2px;
349
+ }
350
+
351
+ .an-rich-md-bubble-button {
352
+ padding: 3px 6px;
353
+ border-radius: 4px;
354
+ font-size: 12px;
355
+ color: hsl(var(--popover-foreground) / 0.76);
356
+ background: none;
357
+ border: none;
358
+ cursor: pointer;
359
+ line-height: 1;
360
+ }
361
+
362
+ .an-rich-md-bubble-button:hover {
363
+ background: hsl(var(--accent));
364
+ color: hsl(var(--accent-foreground));
365
+ }
366
+
367
+ .an-rich-md-bubble-button--active {
368
+ background: hsl(var(--accent));
369
+ color: hsl(var(--accent-foreground));
370
+ }
371
+
372
+ .an-rich-md-bubble-divider {
373
+ width: 1px;
374
+ height: 16px;
375
+ margin: 0 2px;
376
+ background: hsl(var(--border));
377
+ }
378
+
379
+ .an-rich-md-link-editor {
380
+ padding: 4px;
381
+ }
382
+
383
+ .an-rich-md-link-editor input {
384
+ width: 10rem;
385
+ border: none;
386
+ outline: none;
387
+ background: transparent;
388
+ color: hsl(var(--popover-foreground));
389
+ font-size: 12px;
390
+ padding: 2px 4px;
391
+ }
392
+
393
+ .an-rich-md-link-editor button {
394
+ border: none;
395
+ background: none;
396
+ color: hsl(var(--primary));
397
+ cursor: pointer;
398
+ font-size: 11px;
399
+ font-weight: 500;
400
+ padding: 2px 6px;
401
+ }
402
+
403
+ .an-rich-md-slash-menu {
404
+ z-index: 9999;
405
+ width: min(420px, calc(100vw - 24px));
406
+ min-width: 230px;
407
+ max-height: 320px;
408
+ overflow-y: auto;
409
+ color: hsl(var(--foreground));
410
+ background: hsl(var(--popover));
411
+ border: 1px solid hsl(var(--border));
412
+ border-radius: 7px;
413
+ box-shadow:
414
+ 0 4px 20px rgb(0 0 0 / 0.12),
415
+ 0 0 0 1px rgb(0 0 0 / 0.04);
416
+ padding: 4px 0;
417
+ }
418
+
419
+ .an-rich-md-slash-heading {
420
+ padding: 4px 10px;
421
+ font-size: 10px;
422
+ font-weight: 650;
423
+ text-transform: uppercase;
424
+ letter-spacing: 0.06em;
425
+ color: hsl(var(--muted-foreground));
426
+ }
427
+
428
+ .an-rich-md-slash-item {
429
+ width: 100%;
430
+ min-width: 0;
431
+ min-height: 44px;
432
+ display: flex;
433
+ align-items: center;
434
+ gap: 8px;
435
+ padding: 6px 10px;
436
+ text-align: start;
437
+ background: none;
438
+ border: none;
439
+ cursor: pointer;
440
+ color: hsl(var(--foreground));
441
+ font-size: 13px;
442
+ }
443
+
444
+ .an-rich-md-slash-item:hover,
445
+ .an-rich-md-slash-item--active {
446
+ background: hsl(var(--accent));
447
+ }
448
+
449
+ .an-rich-md-slash-icon {
450
+ display: flex;
451
+ align-items: center;
452
+ justify-content: center;
453
+ width: 28px;
454
+ height: 28px;
455
+ border-radius: 4px;
456
+ border: 1px solid hsl(var(--border));
457
+ background: hsl(var(--background));
458
+ font-size: 11px;
459
+ font-weight: 650;
460
+ color: hsl(var(--muted-foreground));
461
+ flex-shrink: 0;
462
+ }
463
+
464
+ .an-rich-md-slash-copy {
465
+ display: block;
466
+ min-width: 0;
467
+ flex: 1;
468
+ }
469
+
470
+ .an-rich-md-slash-title {
471
+ display: block;
472
+ overflow: hidden;
473
+ text-overflow: ellipsis;
474
+ white-space: nowrap;
475
+ font-weight: 500;
476
+ font-size: 13px;
477
+ }
478
+
479
+ .an-rich-md-slash-description {
480
+ display: block;
481
+ overflow: hidden;
482
+ text-overflow: ellipsis;
483
+ white-space: nowrap;
484
+ font-size: 11px;
485
+ color: hsl(var(--muted-foreground));
486
+ }
487
+
488
+ /* Shared block-level image node (the editor's `.an-rich-md-image` and the
489
+ read-only markdown renderer's <img>). Constrained to the prose width and
490
+ responsive; a still-uploading placeholder (empty src) shows a subtle frame. */
491
+ .an-rich-md-prose img,
492
+ .an-rich-md-image {
493
+ display: block;
494
+ max-width: 100%;
495
+ height: auto;
496
+ margin: 12px 0;
497
+ border-radius: 8px;
498
+ }
499
+
500
+ .an-rich-md-image[src=""],
501
+ .an-rich-md-image:not([src]) {
502
+ min-height: 64px;
503
+ background: hsl(var(--muted));
504
+ border: 1px dashed hsl(var(--border));
505
+ }
506
+
507
+ .ProseMirror-selectednode.an-rich-md-image {
508
+ outline: 2px solid hsl(var(--ring));
509
+ outline-offset: 2px;
510
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./use-mobile.js";
2
+ export * from "./use-toast.js";
@@ -0,0 +1,21 @@
1
+ import * as React from "react";
2
+
3
+ const MOBILE_BREAKPOINT = 768;
4
+
5
+ export function useIsMobile() {
6
+ const [isMobile, setIsMobile] = React.useState<boolean | undefined>(
7
+ undefined,
8
+ );
9
+
10
+ React.useEffect(() => {
11
+ const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
12
+ const onChange = () => {
13
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
14
+ };
15
+ mql.addEventListener("change", onChange);
16
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
17
+ return () => mql.removeEventListener("change", onChange);
18
+ }, []);
19
+
20
+ return !!isMobile;
21
+ }
@@ -0,0 +1,188 @@
1
+ import * as React from "react";
2
+
3
+ import type { ToastActionElement, ToastProps } from "../ui/toast.js";
4
+
5
+ const TOAST_LIMIT = 1;
6
+ const TOAST_REMOVE_DELAY = 1000000;
7
+
8
+ type ToasterToast = ToastProps & {
9
+ id: string;
10
+ title?: React.ReactNode;
11
+ description?: React.ReactNode;
12
+ action?: ToastActionElement;
13
+ };
14
+
15
+ const actionTypes = {
16
+ ADD_TOAST: "ADD_TOAST",
17
+ UPDATE_TOAST: "UPDATE_TOAST",
18
+ DISMISS_TOAST: "DISMISS_TOAST",
19
+ REMOVE_TOAST: "REMOVE_TOAST",
20
+ } as const;
21
+
22
+ let count = 0;
23
+
24
+ function genId() {
25
+ count = (count + 1) % Number.MAX_SAFE_INTEGER;
26
+ return count.toString();
27
+ }
28
+
29
+ type ActionType = typeof actionTypes;
30
+
31
+ type Action =
32
+ | {
33
+ type: ActionType["ADD_TOAST"];
34
+ toast: ToasterToast;
35
+ }
36
+ | {
37
+ type: ActionType["UPDATE_TOAST"];
38
+ toast: Partial<ToasterToast>;
39
+ }
40
+ | {
41
+ type: ActionType["DISMISS_TOAST"];
42
+ toastId?: ToasterToast["id"];
43
+ }
44
+ | {
45
+ type: ActionType["REMOVE_TOAST"];
46
+ toastId?: ToasterToast["id"];
47
+ };
48
+
49
+ interface State {
50
+ toasts: ToasterToast[];
51
+ }
52
+
53
+ const toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>();
54
+
55
+ const addToRemoveQueue = (toastId: string) => {
56
+ if (toastTimeouts.has(toastId)) {
57
+ return;
58
+ }
59
+
60
+ const timeout = setTimeout(() => {
61
+ toastTimeouts.delete(toastId);
62
+ dispatch({
63
+ type: "REMOVE_TOAST",
64
+ toastId: toastId,
65
+ });
66
+ }, TOAST_REMOVE_DELAY);
67
+
68
+ toastTimeouts.set(toastId, timeout);
69
+ };
70
+
71
+ export const reducer = (state: State, action: Action): State => {
72
+ switch (action.type) {
73
+ case "ADD_TOAST":
74
+ return {
75
+ ...state,
76
+ toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),
77
+ };
78
+
79
+ case "UPDATE_TOAST":
80
+ return {
81
+ ...state,
82
+ toasts: state.toasts.map((t) =>
83
+ t.id === action.toast.id ? { ...t, ...action.toast } : t,
84
+ ),
85
+ };
86
+
87
+ case "DISMISS_TOAST": {
88
+ const { toastId } = action;
89
+
90
+ // ! Side effects ! - This could be extracted into a dismissToast() action,
91
+ // but I'll keep it here for simplicity
92
+ if (toastId) {
93
+ addToRemoveQueue(toastId);
94
+ } else {
95
+ state.toasts.forEach((toast) => {
96
+ addToRemoveQueue(toast.id);
97
+ });
98
+ }
99
+
100
+ return {
101
+ ...state,
102
+ toasts: state.toasts.map((t) =>
103
+ t.id === toastId || toastId === undefined
104
+ ? {
105
+ ...t,
106
+ open: false,
107
+ }
108
+ : t,
109
+ ),
110
+ };
111
+ }
112
+ case "REMOVE_TOAST":
113
+ if (action.toastId === undefined) {
114
+ return {
115
+ ...state,
116
+ toasts: [],
117
+ };
118
+ }
119
+ return {
120
+ ...state,
121
+ toasts: state.toasts.filter((t) => t.id !== action.toastId),
122
+ };
123
+ }
124
+ };
125
+
126
+ const listeners: Array<(state: State) => void> = [];
127
+
128
+ let memoryState: State = { toasts: [] };
129
+
130
+ function dispatch(action: Action) {
131
+ memoryState = reducer(memoryState, action);
132
+ listeners.forEach((listener) => {
133
+ listener(memoryState);
134
+ });
135
+ }
136
+
137
+ type Toast = Omit<ToasterToast, "id">;
138
+
139
+ function toast({ ...props }: Toast) {
140
+ const id = genId();
141
+
142
+ const update = (props: ToasterToast) =>
143
+ dispatch({
144
+ type: "UPDATE_TOAST",
145
+ toast: { ...props, id },
146
+ });
147
+ const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id });
148
+
149
+ dispatch({
150
+ type: "ADD_TOAST",
151
+ toast: {
152
+ ...props,
153
+ id,
154
+ open: true,
155
+ onOpenChange: (open: boolean) => {
156
+ if (!open) dismiss();
157
+ },
158
+ },
159
+ });
160
+
161
+ return {
162
+ id: id,
163
+ dismiss,
164
+ update,
165
+ };
166
+ }
167
+
168
+ function useToast() {
169
+ const [state, setState] = React.useState<State>(memoryState);
170
+
171
+ React.useEffect(() => {
172
+ listeners.push(setState);
173
+ return () => {
174
+ const index = listeners.indexOf(setState);
175
+ if (index > -1) {
176
+ listeners.splice(index, 1);
177
+ }
178
+ };
179
+ }, [state]);
180
+
181
+ return {
182
+ ...state,
183
+ toast,
184
+ dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }),
185
+ };
186
+ }
187
+
188
+ export { useToast, toast };
package/src/index.ts ADDED
@@ -0,0 +1,8 @@
1
+ export * from "./app-shell/index.js";
2
+ export * from "./collab-ui/index.js";
3
+ export * from "./hooks/index.js";
4
+ export * from "./onboarding/index.js";
5
+ export * from "./provider.js";
6
+ export * from "./sharing/index.js";
7
+ export * from "./ui/index.js";
8
+ export * from "./utils.js";