@refraction-ui/astro 0.4.2 → 0.4.5

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 (334) hide show
  1. package/dist/accordion/index.ts +1 -0
  2. package/dist/ai/ai-manager.ts +121 -0
  3. package/dist/ai/index.ts +23 -0
  4. package/dist/ai/mock-providers.ts +68 -0
  5. package/dist/ai/sanitizer.ts +174 -0
  6. package/dist/ai/tts-manager.ts +80 -0
  7. package/dist/ai/types.ts +72 -0
  8. package/dist/animated-text/animated-text.styles.ts +28 -0
  9. package/dist/animated-text/animated-text.ts +83 -0
  10. package/dist/animated-text/index.ts +15 -0
  11. package/dist/app-shell/app-shell.ts +252 -0
  12. package/dist/app-shell/auth-shell.ts +84 -0
  13. package/dist/app-shell/index.ts +22 -0
  14. package/dist/app-shell/page-shell.ts +125 -0
  15. package/dist/astro-accordion/Button.astro +1 -1
  16. package/dist/astro-ai/index.ts +1 -1
  17. package/dist/astro-animated-text/AnimatedText.astro +1 -1
  18. package/dist/astro-animated-text/TypewriterText.astro +1 -1
  19. package/dist/astro-app-shell/AppShell.astro +1 -1
  20. package/dist/astro-app-shell/AuthShell.astro +1 -1
  21. package/dist/astro-app-shell/AuthShellCard.astro +1 -1
  22. package/dist/astro-app-shell/PageShell.astro +1 -1
  23. package/dist/astro-app-shell/PageShellSection.astro +1 -1
  24. package/dist/astro-app-shell/index.ts +1 -1
  25. package/dist/astro-auth/index.ts +2 -2
  26. package/dist/astro-avatar/Avatar.astro +1 -1
  27. package/dist/astro-avatar/AvatarFallback.astro +1 -1
  28. package/dist/astro-avatar/AvatarImage.astro +1 -1
  29. package/dist/astro-avatar-group/AvatarGroup.astro +1 -1
  30. package/dist/astro-badge/Badge.astro +1 -1
  31. package/dist/astro-bottom-nav/BottomNav.astro +1 -1
  32. package/dist/astro-breadcrumbs/Breadcrumbs.astro +1 -1
  33. package/dist/astro-button/Button.astro +1 -1
  34. package/dist/astro-calendar/Calendar.astro +1 -1
  35. package/dist/astro-card/Card.astro +1 -1
  36. package/dist/astro-card/CardContent.astro +1 -1
  37. package/dist/astro-card/CardDescription.astro +1 -1
  38. package/dist/astro-card/CardFooter.astro +1 -1
  39. package/dist/astro-card/CardHeader.astro +1 -1
  40. package/dist/astro-card/CardTitle.astro +1 -1
  41. package/dist/astro-card-grid/CardGrid.astro +1 -1
  42. package/dist/astro-carousel/Button.astro +1 -1
  43. package/dist/astro-charts/Bars.astro +1 -1
  44. package/dist/astro-charts/Chart.astro +1 -1
  45. package/dist/astro-charts/Circles.astro +1 -1
  46. package/dist/astro-charts/Histogram.astro +1 -1
  47. package/dist/astro-charts/Line.astro +1 -1
  48. package/dist/astro-charts/PieChart.astro +1 -1
  49. package/dist/astro-charts/ScatterPlot.astro +1 -1
  50. package/dist/astro-charts/index.ts +1 -1
  51. package/dist/astro-checkbox/Checkbox.astro +1 -1
  52. package/dist/astro-code-editor/CodeEditor.astro +1 -1
  53. package/dist/astro-collapsible/Collapsible.astro +1 -1
  54. package/dist/astro-collapsible/CollapsibleContent.astro +1 -1
  55. package/dist/astro-command/Command.astro +1 -1
  56. package/dist/astro-command/CommandGroup.astro +1 -1
  57. package/dist/astro-command/CommandInput.astro +1 -1
  58. package/dist/astro-command/CommandItem.astro +1 -1
  59. package/dist/astro-command-input/CommandInput.astro +1 -1
  60. package/dist/astro-content-protection/ContentProtection.astro +1 -1
  61. package/dist/astro-data-table/DataTable.astro +1 -1
  62. package/dist/astro-date-picker/DatePicker.astro +1 -1
  63. package/dist/astro-device-frame/DeviceFrame.astro +1 -1
  64. package/dist/astro-dialog/DialogContent.astro +1 -1
  65. package/dist/astro-dialog/DialogOverlay.astro +1 -1
  66. package/dist/astro-diff-viewer/DiffViewer.astro +1 -1
  67. package/dist/astro-dropdown-menu/DropdownMenuContent.astro +1 -1
  68. package/dist/astro-dropdown-menu/DropdownMenuItem.astro +1 -1
  69. package/dist/astro-emoji-picker/EmojiPicker.astro +1 -1
  70. package/dist/astro-feedback-dialog/FeedbackDialog.astro +1 -1
  71. package/dist/astro-file-upload/FileUpload.astro +1 -1
  72. package/dist/astro-footer/Footer.astro +1 -1
  73. package/dist/astro-inline-editor/InlineEditor.astro +1 -1
  74. package/dist/astro-input/Input.astro +1 -1
  75. package/dist/astro-input-group/InputGroup.astro +1 -1
  76. package/dist/astro-input-group/InputGroupAddon.astro +1 -1
  77. package/dist/astro-input-group/InputGroupButton.astro +1 -1
  78. package/dist/astro-install-prompt/InstallPrompt.astro +1 -1
  79. package/dist/astro-keyboard-shortcut/ShortcutBadge.astro +1 -1
  80. package/dist/astro-language-selector/LanguageSelector.astro +1 -1
  81. package/dist/astro-link-card/LinkCard.astro +1 -1
  82. package/dist/astro-markdown-renderer/MarkdownRenderer.astro +1 -1
  83. package/dist/astro-mobile-nav/MobileNav.astro +1 -1
  84. package/dist/astro-mobile-nav/MobileNavLink.astro +1 -1
  85. package/dist/astro-mobile-nav/MobileNavTrigger.astro +1 -1
  86. package/dist/astro-navbar/Navbar.astro +1 -1
  87. package/dist/astro-otp-input/OtpInput.astro +1 -1
  88. package/dist/astro-payment/Payment.astro +1 -1
  89. package/dist/astro-popover/PopoverContent.astro +1 -1
  90. package/dist/astro-presence-indicator/PresenceIndicator.astro +1 -1
  91. package/dist/astro-progress-display/BadgeDisplay.astro +1 -1
  92. package/dist/astro-progress-display/ProgressBar.astro +1 -1
  93. package/dist/astro-progress-display/StatsGrid.astro +1 -1
  94. package/dist/astro-radio/RadioGroup.astro +1 -1
  95. package/dist/astro-radio/RadioItem.astro +1 -1
  96. package/dist/astro-reaction-bar/ReactionBar.astro +1 -1
  97. package/dist/astro-resizable-layout/ResizableDivider.astro +1 -1
  98. package/dist/astro-resizable-layout/ResizableLayout.astro +1 -1
  99. package/dist/astro-resizable-layout/ResizablePane.astro +1 -1
  100. package/dist/astro-resizable-layout/index.ts +1 -1
  101. package/dist/astro-rich-editor/index.ts +2 -2
  102. package/dist/astro-search-bar/SearchBar.astro +1 -1
  103. package/dist/astro-search-bar/SearchResults.astro +1 -1
  104. package/dist/astro-select/Select.astro +1 -1
  105. package/dist/astro-select/SelectContent.astro +1 -1
  106. package/dist/astro-select/SelectItem.astro +1 -1
  107. package/dist/astro-select/SelectTrigger.astro +1 -1
  108. package/dist/astro-sidebar/Sidebar.astro +1 -1
  109. package/dist/astro-skeleton/Skeleton.astro +1 -1
  110. package/dist/astro-slide-viewer/SlideViewer.astro +1 -1
  111. package/dist/astro-status-indicator/StatusIndicator.astro +1 -1
  112. package/dist/astro-switch/Switch.astro +1 -1
  113. package/dist/astro-table-of-contents/TableOfContents.astro +1 -1
  114. package/dist/astro-tabs/Tabs.astro +1 -1
  115. package/dist/astro-tabs/TabsList.astro +1 -1
  116. package/dist/astro-tabs/TabsTrigger.astro +1 -1
  117. package/dist/astro-textarea/Textarea.astro +1 -1
  118. package/dist/astro-theme/ThemeScript.astro +1 -1
  119. package/dist/astro-thread-view/ThreadView.astro +1 -1
  120. package/dist/astro-toast/Toast.astro +1 -1
  121. package/dist/astro-tooltip/TooltipContent.astro +1 -1
  122. package/dist/astro-version-selector/VersionSelector.astro +1 -1
  123. package/dist/astro-video-player/VideoPlayer.astro +1 -1
  124. package/dist/auth/adapters/mock.ts +74 -0
  125. package/dist/auth/auth-machine.ts +120 -0
  126. package/dist/auth/index.ts +22 -0
  127. package/dist/auth/rbac.ts +44 -0
  128. package/dist/auth/types.ts +44 -0
  129. package/dist/avatar/avatar.styles.ts +47 -0
  130. package/dist/avatar/avatar.ts +73 -0
  131. package/dist/avatar/index.ts +15 -0
  132. package/dist/avatar-group/avatar-group.styles.ts +63 -0
  133. package/dist/avatar-group/avatar-group.ts +106 -0
  134. package/dist/avatar-group/index.ts +18 -0
  135. package/dist/badge/badge.styles.ts +24 -0
  136. package/dist/badge/badge.ts +48 -0
  137. package/dist/badge/index.ts +10 -0
  138. package/dist/bottom-nav/bottom-nav.styles.ts +18 -0
  139. package/dist/bottom-nav/bottom-nav.ts +33 -0
  140. package/dist/bottom-nav/index.ts +2 -0
  141. package/dist/breadcrumbs/breadcrumbs.styles.ts +20 -0
  142. package/dist/breadcrumbs/breadcrumbs.ts +72 -0
  143. package/dist/breadcrumbs/index.ts +8 -0
  144. package/dist/button/button.styles.ts +38 -0
  145. package/dist/button/button.ts +64 -0
  146. package/dist/button/index.ts +10 -0
  147. package/dist/calendar/calendar.styles.ts +21 -0
  148. package/dist/calendar/calendar.ts +202 -0
  149. package/dist/calendar/index.ts +9 -0
  150. package/dist/callout/callout.ts +1 -0
  151. package/dist/callout/index.ts +1 -0
  152. package/dist/card/card.styles.ts +55 -0
  153. package/dist/card/card.ts +45 -0
  154. package/dist/card/index.ts +20 -0
  155. package/dist/card-grid/card-grid.ts +9 -0
  156. package/dist/card-grid/index.ts +1 -0
  157. package/dist/carousel/index.ts +1 -0
  158. package/dist/charts/axis.ts +50 -0
  159. package/dist/charts/chart.ts +73 -0
  160. package/dist/charts/colorblind.ts +100 -0
  161. package/dist/charts/data.ts +72 -0
  162. package/dist/charts/geometry.ts +54 -0
  163. package/dist/charts/index.ts +61 -0
  164. package/dist/charts/scales.ts +151 -0
  165. package/dist/checkbox/checkbox.styles.ts +33 -0
  166. package/dist/checkbox/checkbox.ts +73 -0
  167. package/dist/checkbox/index.ts +10 -0
  168. package/dist/code-block/code-block.ts +1 -0
  169. package/dist/code-block/index.ts +1 -0
  170. package/dist/code-editor/code-editor.styles.ts +32 -0
  171. package/dist/code-editor/code-editor.ts +140 -0
  172. package/dist/code-editor/index.ts +9 -0
  173. package/dist/collapsible/collapsible.styles.ts +14 -0
  174. package/dist/collapsible/collapsible.ts +93 -0
  175. package/dist/collapsible/index.ts +7 -0
  176. package/dist/command/command.styles.ts +27 -0
  177. package/dist/command/command.ts +179 -0
  178. package/dist/command/index.ts +14 -0
  179. package/dist/command-input/command-input.ts +176 -0
  180. package/dist/command-input/index.ts +1 -0
  181. package/dist/content-protection/content-protection.styles.ts +9 -0
  182. package/dist/content-protection/content-protection.ts +68 -0
  183. package/dist/content-protection/index.ts +8 -0
  184. package/dist/data-table/data-table.styles.ts +55 -0
  185. package/dist/data-table/data-table.ts +183 -0
  186. package/dist/data-table/index.ts +15 -0
  187. package/dist/date-picker/date-picker.styles.ts +31 -0
  188. package/dist/date-picker/date-picker.ts +333 -0
  189. package/dist/date-picker/index.ts +18 -0
  190. package/dist/device-frame/device-frame.styles.ts +21 -0
  191. package/dist/device-frame/device-frame.ts +112 -0
  192. package/dist/device-frame/index.ts +10 -0
  193. package/dist/dialog/dialog.styles.ts +8 -0
  194. package/dist/dialog/dialog.ts +133 -0
  195. package/dist/dialog/index.ts +8 -0
  196. package/dist/diff-viewer/diff-viewer.styles.ts +124 -0
  197. package/dist/diff-viewer/diff-viewer.ts +255 -0
  198. package/dist/diff-viewer/index.ts +20 -0
  199. package/dist/dropdown-menu/dropdown-menu.styles.ts +9 -0
  200. package/dist/dropdown-menu/dropdown-menu.ts +139 -0
  201. package/dist/dropdown-menu/index.ts +9 -0
  202. package/dist/emoji-picker/emoji-data.ts +282 -0
  203. package/dist/emoji-picker/emoji-picker.styles.ts +32 -0
  204. package/dist/emoji-picker/emoji-picker.ts +165 -0
  205. package/dist/emoji-picker/index.ts +25 -0
  206. package/dist/feedback-dialog/feedback-dialog.styles.ts +15 -0
  207. package/dist/feedback-dialog/feedback-dialog.ts +147 -0
  208. package/dist/feedback-dialog/index.ts +11 -0
  209. package/dist/file-upload/file-upload.styles.ts +30 -0
  210. package/dist/file-upload/file-upload.ts +260 -0
  211. package/dist/file-upload/index.ts +19 -0
  212. package/dist/footer/footer.styles.ts +5 -0
  213. package/dist/footer/footer.ts +32 -0
  214. package/dist/footer/index.ts +9 -0
  215. package/dist/index.ts +1 -1
  216. package/dist/inline-editor/index.ts +13 -0
  217. package/dist/inline-editor/inline-editor.styles.ts +42 -0
  218. package/dist/inline-editor/inline-editor.ts +96 -0
  219. package/dist/input/index.ts +9 -0
  220. package/dist/input/input.styles.ts +15 -0
  221. package/dist/input/input.ts +84 -0
  222. package/dist/input-group/index.ts +13 -0
  223. package/dist/input-group/input-group.styles.ts +50 -0
  224. package/dist/input-group/input-group.ts +44 -0
  225. package/dist/install-prompt/index.ts +9 -0
  226. package/dist/install-prompt/install-prompt.styles.ts +5 -0
  227. package/dist/install-prompt/install-prompt.ts +68 -0
  228. package/dist/keyboard-shortcut/index.ts +12 -0
  229. package/dist/keyboard-shortcut/keyboard-shortcut.styles.ts +8 -0
  230. package/dist/keyboard-shortcut/keyboard-shortcut.ts +153 -0
  231. package/dist/language-selector/index.ts +8 -0
  232. package/dist/language-selector/language-selector.styles.ts +28 -0
  233. package/dist/language-selector/language-selector.ts +149 -0
  234. package/dist/link-card/index.ts +1 -0
  235. package/dist/link-card/link-card.ts +9 -0
  236. package/dist/markdown-renderer/index.ts +8 -0
  237. package/dist/markdown-renderer/markdown-renderer.styles.ts +31 -0
  238. package/dist/markdown-renderer/markdown-renderer.ts +251 -0
  239. package/dist/mobile-nav/index.ts +14 -0
  240. package/dist/mobile-nav/mobile-nav.styles.ts +39 -0
  241. package/dist/mobile-nav/mobile-nav.ts +74 -0
  242. package/dist/navbar/index.ts +9 -0
  243. package/dist/navbar/navbar.styles.ts +29 -0
  244. package/dist/navbar/navbar.ts +39 -0
  245. package/dist/otp-input/index.ts +13 -0
  246. package/dist/otp-input/otp-input.styles.ts +51 -0
  247. package/dist/otp-input/otp-input.ts +198 -0
  248. package/dist/pagination/index.ts +1 -0
  249. package/dist/payment/index.ts +1 -0
  250. package/dist/payment/payment.ts +16 -0
  251. package/dist/popover/index.ts +7 -0
  252. package/dist/popover/popover.styles.ts +16 -0
  253. package/dist/popover/popover.ts +89 -0
  254. package/dist/presence-indicator/index.ts +14 -0
  255. package/dist/presence-indicator/presence-indicator.styles.ts +29 -0
  256. package/dist/presence-indicator/presence-indicator.ts +63 -0
  257. package/dist/progress-display/index.ts +15 -0
  258. package/dist/progress-display/progress-display.styles.ts +72 -0
  259. package/dist/progress-display/progress-display.ts +60 -0
  260. package/dist/radio/index.ts +8 -0
  261. package/dist/radio/radio.styles.ts +34 -0
  262. package/dist/radio/radio.ts +70 -0
  263. package/dist/reaction-bar/index.ts +14 -0
  264. package/dist/reaction-bar/reaction-bar.styles.ts +23 -0
  265. package/dist/reaction-bar/reaction-bar.ts +87 -0
  266. package/dist/resizable-layout/index.ts +12 -0
  267. package/dist/resizable-layout/resizable-layout.styles.ts +50 -0
  268. package/dist/resizable-layout/resizable-layout.ts +139 -0
  269. package/dist/rich-editor/editor.ts +342 -0
  270. package/dist/rich-editor/emoji.ts +175 -0
  271. package/dist/rich-editor/history.ts +79 -0
  272. package/dist/rich-editor/index.ts +106 -0
  273. package/dist/rich-editor/markdown-shortcuts.ts +248 -0
  274. package/dist/rich-editor/mentions.ts +162 -0
  275. package/dist/rich-editor/model.ts +206 -0
  276. package/dist/rich-editor/operations.ts +772 -0
  277. package/dist/rich-editor/selection.ts +157 -0
  278. package/dist/rich-editor/serialization.ts +711 -0
  279. package/dist/rich-editor/slash-commands.ts +212 -0
  280. package/dist/search-bar/index.ts +7 -0
  281. package/dist/search-bar/search-bar.styles.ts +29 -0
  282. package/dist/search-bar/search-bar.ts +130 -0
  283. package/dist/select/index.ts +13 -0
  284. package/dist/select/select.styles.ts +52 -0
  285. package/dist/select/select.ts +152 -0
  286. package/dist/sidebar/index.ts +9 -0
  287. package/dist/sidebar/sidebar.styles.ts +27 -0
  288. package/dist/sidebar/sidebar.ts +59 -0
  289. package/dist/skeleton/index.ts +8 -0
  290. package/dist/skeleton/skeleton.styles.ts +16 -0
  291. package/dist/skeleton/skeleton.ts +39 -0
  292. package/dist/skip-to-content/index.ts +1 -0
  293. package/dist/skip-to-content/skip-to-content.ts +1 -0
  294. package/dist/slide-viewer/index.ts +16 -0
  295. package/dist/slide-viewer/slide-viewer.styles.ts +57 -0
  296. package/dist/slide-viewer/slide-viewer.ts +152 -0
  297. package/dist/slider/index.ts +1 -0
  298. package/dist/slider/slider.ts +2 -0
  299. package/dist/status-indicator/index.ts +15 -0
  300. package/dist/status-indicator/status-indicator.styles.ts +41 -0
  301. package/dist/status-indicator/status-indicator.ts +66 -0
  302. package/dist/steps/index.ts +1 -0
  303. package/dist/steps/steps.ts +1 -0
  304. package/dist/switch/index.ts +7 -0
  305. package/dist/switch/switch.styles.ts +55 -0
  306. package/dist/switch/switch.ts +63 -0
  307. package/dist/table-of-contents/index.ts +1 -0
  308. package/dist/table-of-contents/table-of-contents.ts +37 -0
  309. package/dist/tabs/index.ts +8 -0
  310. package/dist/tabs/tabs.styles.ts +9 -0
  311. package/dist/tabs/tabs.ts +133 -0
  312. package/dist/textarea/index.ts +7 -0
  313. package/dist/textarea/textarea.styles.ts +15 -0
  314. package/dist/textarea/textarea.ts +59 -0
  315. package/dist/theme/dom-adapters.ts +60 -0
  316. package/dist/theme/index.ts +18 -0
  317. package/dist/theme/theme-machine.ts +130 -0
  318. package/dist/theme/theme-script.ts +18 -0
  319. package/dist/thread-view/index.ts +26 -0
  320. package/dist/thread-view/thread-view.styles.ts +35 -0
  321. package/dist/thread-view/thread-view.ts +176 -0
  322. package/dist/toast/index.ts +13 -0
  323. package/dist/toast/toast.styles.ts +19 -0
  324. package/dist/toast/toast.ts +203 -0
  325. package/dist/tooltip/index.ts +7 -0
  326. package/dist/tooltip/tooltip.styles.ts +16 -0
  327. package/dist/tooltip/tooltip.ts +109 -0
  328. package/dist/version-selector/index.ts +12 -0
  329. package/dist/version-selector/version-selector.styles.ts +41 -0
  330. package/dist/version-selector/version-selector.ts +136 -0
  331. package/dist/video-player/index.ts +12 -0
  332. package/dist/video-player/video-player.styles.ts +42 -0
  333. package/dist/video-player/video-player.ts +100 -0
  334. package/package.json +1 -1
@@ -0,0 +1,342 @@
1
+ /**
2
+ * Main editor factory — ties together all subsystems into a unified API.
3
+ */
4
+
5
+ import type {
6
+ Document,
7
+ Mark,
8
+ MarkType,
9
+ BlockType,
10
+ } from './model.js'
11
+ import {
12
+ createDocument,
13
+ getBlockTextLength,
14
+ } from './model.js'
15
+ import type { Selection } from './selection.js'
16
+ import {
17
+ selectionAtDocStart,
18
+ } from './selection.js'
19
+ import type { EditorState } from './operations.js'
20
+ import {
21
+ insertText as opInsertText,
22
+ deleteBackward as opDeleteBackward,
23
+ deleteForward as opDeleteForward,
24
+ splitBlock as opSplitBlock,
25
+ changeBlockType as opChangeBlockType,
26
+ indentBlock as opIndentBlock,
27
+ outdentBlock as opOutdentBlock,
28
+ toggleMark as opToggleMark,
29
+ getActiveMarks as opGetActiveMarks,
30
+ } from './operations.js'
31
+ import { processMarkdownShortcut } from './markdown-shortcuts.js'
32
+ import type { SlashCommand, SlashCommandMenu } from './slash-commands.js'
33
+ import { createSlashCommandMenu } from './slash-commands.js'
34
+ import type { MentionOption, MentionMenu } from './mentions.js'
35
+ import { createMentionMenu } from './mentions.js'
36
+ import { toMarkdown, fromMarkdown, toHTML, toPlainText } from './serialization.js'
37
+
38
+ // ---------------------------------------------------------------------------
39
+ // Types
40
+ // ---------------------------------------------------------------------------
41
+
42
+ export interface EditorConfig {
43
+ initialContent?: Document | string
44
+ placeholder?: string
45
+ readOnly?: boolean
46
+ maxLength?: number
47
+ slashCommands?: SlashCommand[]
48
+ mentionOptions?: MentionOption[]
49
+ onUpdate?: (state: EditorState) => void
50
+ }
51
+
52
+ export interface EditorAPI {
53
+ // State
54
+ getState(): EditorState
55
+ getDoc(): Document
56
+ getSelection(): Selection
57
+
58
+ // Content
59
+ insertText(text: string): void
60
+ deleteBackward(): void
61
+ deleteForward(): void
62
+ toggleMark(mark: MarkType): void
63
+ changeBlockType(type: BlockType, meta?: Record<string, unknown>): void
64
+ splitBlock(): void
65
+ indentBlock(): void
66
+ outdentBlock(): void
67
+
68
+ // Markdown
69
+ getMarkdown(): string
70
+ getHTML(): string
71
+ getPlainText(): string
72
+ setContent(markdown: string): void
73
+
74
+ // Menus
75
+ slashMenu: SlashCommandMenu
76
+ mentionMenu: MentionMenu
77
+
78
+ // History
79
+ undo(): void
80
+ redo(): void
81
+ canUndo(): boolean
82
+ canRedo(): boolean
83
+
84
+ // Marks
85
+ getActiveMarks(): Mark[]
86
+ isMarkActive(type: MarkType): boolean
87
+
88
+ // State queries
89
+ isEmpty(): boolean
90
+ getCharCount(): number
91
+ getWordCount(): number
92
+
93
+ // Events
94
+ subscribe(fn: (state: EditorState) => void): () => void
95
+ destroy(): void
96
+ }
97
+
98
+ // ---------------------------------------------------------------------------
99
+ // Factory
100
+ // ---------------------------------------------------------------------------
101
+
102
+ export function createEditor(config?: EditorConfig): EditorAPI {
103
+ const {
104
+ initialContent,
105
+ placeholder,
106
+ readOnly = false,
107
+ maxLength,
108
+ slashCommands,
109
+ mentionOptions = [],
110
+ onUpdate,
111
+ } = config ?? {}
112
+
113
+ // Initialize document
114
+ let doc: Document = (() => {
115
+ if (!initialContent) return createDocument()
116
+ if (typeof initialContent === 'string') return fromMarkdown(initialContent)
117
+ return JSON.parse(JSON.stringify(initialContent)) as Document
118
+ })()
119
+
120
+ let selection: Selection = selectionAtDocStart(doc)
121
+ const slashMenu = createSlashCommandMenu(slashCommands)
122
+ const mentionMenuInstance = createMentionMenu(mentionOptions)
123
+ const subscribers: Set<(state: EditorState) => void> = new Set()
124
+
125
+ // Internal undo/redo stacks (stores pre-edit snapshots)
126
+ let undoStack: EditorState[] = []
127
+ let redoStack: EditorState[] = []
128
+ const MAX_HISTORY = 100
129
+
130
+ function cloneState(): EditorState {
131
+ return JSON.parse(JSON.stringify({ doc, selection })) as EditorState
132
+ }
133
+
134
+ function getState(): EditorState {
135
+ return { doc, selection }
136
+ }
137
+
138
+ function notify(): void {
139
+ const state = getState()
140
+ for (const fn of subscribers) {
141
+ fn(state)
142
+ }
143
+ onUpdate?.(state)
144
+ }
145
+
146
+ function pushHistory(): void {
147
+ undoStack.push(cloneState())
148
+ if (undoStack.length > MAX_HISTORY) {
149
+ undoStack = undoStack.slice(undoStack.length - MAX_HISTORY)
150
+ }
151
+ // New edit clears redo
152
+ redoStack = []
153
+ }
154
+
155
+ function getPlainTextContent(): string {
156
+ return toPlainText(doc)
157
+ }
158
+
159
+ function checkMaxLength(text: string): boolean {
160
+ if (maxLength === undefined) return true
161
+ const currentLen = getPlainTextContent().length
162
+ return currentLen + text.length <= maxLength
163
+ }
164
+
165
+ // ---------------------------------------------------------------------------
166
+ // API
167
+ // ---------------------------------------------------------------------------
168
+
169
+ const api: EditorAPI = {
170
+ getState,
171
+ getDoc: () => doc,
172
+ getSelection: () => selection,
173
+
174
+ insertText(text: string): void {
175
+ if (readOnly) return
176
+ if (!checkMaxLength(text)) return
177
+
178
+ pushHistory()
179
+
180
+ // Check markdown shortcuts for single character input
181
+ if (text.length === 1) {
182
+ const shortcutResult = processMarkdownShortcut(doc, selection, text)
183
+ if (shortcutResult.consumed) {
184
+ doc = shortcutResult.doc
185
+ selection = shortcutResult.sel
186
+ notify()
187
+ return
188
+ }
189
+ }
190
+
191
+ const result = opInsertText(doc, selection, text)
192
+ doc = result.doc
193
+ selection = result.selection
194
+ notify()
195
+ },
196
+
197
+ deleteBackward(): void {
198
+ if (readOnly) return
199
+ pushHistory()
200
+ const result = opDeleteBackward(doc, selection)
201
+ doc = result.doc
202
+ selection = result.selection
203
+ notify()
204
+ },
205
+
206
+ deleteForward(): void {
207
+ if (readOnly) return
208
+ pushHistory()
209
+ const result = opDeleteForward(doc, selection)
210
+ doc = result.doc
211
+ selection = result.selection
212
+ notify()
213
+ },
214
+
215
+ toggleMark(mark: MarkType): void {
216
+ if (readOnly) return
217
+ pushHistory()
218
+ const result = opToggleMark(doc, selection, mark)
219
+ doc = result.doc
220
+ selection = result.selection
221
+ notify()
222
+ },
223
+
224
+ changeBlockType(type: BlockType, meta?: Record<string, unknown>): void {
225
+ if (readOnly) return
226
+ pushHistory()
227
+ const result = opChangeBlockType(doc, selection, type, meta)
228
+ doc = result.doc
229
+ selection = result.selection
230
+ notify()
231
+ },
232
+
233
+ splitBlock(): void {
234
+ if (readOnly) return
235
+ pushHistory()
236
+ const result = opSplitBlock(doc, selection)
237
+ doc = result.doc
238
+ selection = result.selection
239
+ notify()
240
+ },
241
+
242
+ indentBlock(): void {
243
+ if (readOnly) return
244
+ pushHistory()
245
+ const result = opIndentBlock(doc, selection)
246
+ doc = result.doc
247
+ selection = result.selection
248
+ notify()
249
+ },
250
+
251
+ outdentBlock(): void {
252
+ if (readOnly) return
253
+ pushHistory()
254
+ const result = opOutdentBlock(doc, selection)
255
+ doc = result.doc
256
+ selection = result.selection
257
+ notify()
258
+ },
259
+
260
+ getMarkdown: () => toMarkdown(doc),
261
+ getHTML: () => toHTML(doc),
262
+ getPlainText: () => toPlainText(doc),
263
+
264
+ setContent(markdown: string): void {
265
+ pushHistory()
266
+ doc = fromMarkdown(markdown)
267
+ selection = selectionAtDocStart(doc)
268
+ notify()
269
+ },
270
+
271
+ slashMenu,
272
+ mentionMenu: mentionMenuInstance,
273
+
274
+ undo(): void {
275
+ if (undoStack.length === 0) return
276
+ // Save current state to redo stack
277
+ redoStack.push(cloneState())
278
+ // Restore from undo stack
279
+ const state = undoStack.pop()!
280
+ doc = state.doc
281
+ selection = state.selection
282
+ notify()
283
+ },
284
+
285
+ redo(): void {
286
+ if (redoStack.length === 0) return
287
+ // Save current state to undo stack
288
+ undoStack.push(cloneState())
289
+ // Restore from redo stack
290
+ const state = redoStack.pop()!
291
+ doc = state.doc
292
+ selection = state.selection
293
+ notify()
294
+ },
295
+
296
+ canUndo: () => undoStack.length > 0,
297
+ canRedo: () => redoStack.length > 0,
298
+
299
+ getActiveMarks(): Mark[] {
300
+ return opGetActiveMarks(doc, selection)
301
+ },
302
+
303
+ isMarkActive(type: MarkType): boolean {
304
+ return opGetActiveMarks(doc, selection).some((m) => m.type === type)
305
+ },
306
+
307
+ isEmpty(): boolean {
308
+ if (doc.blocks.length === 0) return true
309
+ if (doc.blocks.length > 1) return false
310
+ const block = doc.blocks[0]
311
+ return getBlockTextLength(block) === 0
312
+ },
313
+
314
+ getCharCount(): number {
315
+ let count = 0
316
+ for (const block of doc.blocks) {
317
+ count += getBlockTextLength(block)
318
+ }
319
+ return count
320
+ },
321
+
322
+ getWordCount(): number {
323
+ const text = toPlainText(doc)
324
+ const trimmed = text.trim()
325
+ if (trimmed === '') return 0
326
+ return trimmed.split(/\s+/).length
327
+ },
328
+
329
+ subscribe(fn: (state: EditorState) => void): () => void {
330
+ subscribers.add(fn)
331
+ return () => { subscribers.delete(fn) }
332
+ },
333
+
334
+ destroy(): void {
335
+ subscribers.clear()
336
+ undoStack = []
337
+ redoStack = []
338
+ },
339
+ }
340
+
341
+ return api
342
+ }
@@ -0,0 +1,175 @@
1
+ /**
2
+ * Emoji system — shortcode to unicode mapping and search.
3
+ */
4
+
5
+ // ---------------------------------------------------------------------------
6
+ // Emoji map
7
+ // ---------------------------------------------------------------------------
8
+
9
+ export const EMOJI_MAP: Record<string, string> = {
10
+ ':smile:': '\u{1F604}',
11
+ ':laugh:': '\u{1F602}',
12
+ ':joy:': '\u{1F602}',
13
+ ':grin:': '\u{1F601}',
14
+ ':wink:': '\u{1F609}',
15
+ ':blush:': '\u{1F60A}',
16
+ ':heart_eyes:': '\u{1F60D}',
17
+ ':kissing:': '\u{1F617}',
18
+ ':thinking:': '\u{1F914}',
19
+ ':neutral:': '\u{1F610}',
20
+ ':expressionless:': '\u{1F611}',
21
+ ':unamused:': '\u{1F612}',
22
+ ':sweat:': '\u{1F613}',
23
+ ':pensive:': '\u{1F614}',
24
+ ':confused:': '\u{1F615}',
25
+ ':disappointed:': '\u{1F61E}',
26
+ ':worried:': '\u{1F61F}',
27
+ ':angry:': '\u{1F620}',
28
+ ':rage:': '\u{1F621}',
29
+ ':cry:': '\u{1F622}',
30
+ ':sob:': '\u{1F62D}',
31
+ ':scream:': '\u{1F631}',
32
+ ':fearful:': '\u{1F628}',
33
+ ':cold_sweat:': '\u{1F630}',
34
+ ':relieved:': '\u{1F60C}',
35
+ ':sleepy:': '\u{1F62A}',
36
+ ':sleeping:': '\u{1F634}',
37
+ ':mask:': '\u{1F637}',
38
+ ':sunglasses:': '\u{1F60E}',
39
+ ':nerd:': '\u{1F913}',
40
+ ':heart:': '\u{2764}\u{FE0F}',
41
+ ':broken_heart:': '\u{1F494}',
42
+ ':sparkling_heart:': '\u{1F496}',
43
+ ':two_hearts:': '\u{1F495}',
44
+ ':fire:': '\u{1F525}',
45
+ ':100:': '\u{1F4AF}',
46
+ ':star:': '\u{2B50}',
47
+ ':star2:': '\u{1F31F}',
48
+ ':sparkles:': '\u{2728}',
49
+ ':thumbsup:': '\u{1F44D}',
50
+ ':thumbsdown:': '\u{1F44E}',
51
+ ':wave:': '\u{1F44B}',
52
+ ':clap:': '\u{1F44F}',
53
+ ':raised_hands:': '\u{1F64C}',
54
+ ':pray:': '\u{1F64F}',
55
+ ':muscle:': '\u{1F4AA}',
56
+ ':point_up:': '\u{261D}\u{FE0F}',
57
+ ':point_down:': '\u{1F447}',
58
+ ':point_left:': '\u{1F448}',
59
+ ':point_right:': '\u{1F449}',
60
+ ':ok_hand:': '\u{1F44C}',
61
+ ':v:': '\u{270C}\u{FE0F}',
62
+ ':eyes:': '\u{1F440}',
63
+ ':tongue:': '\u{1F445}',
64
+ ':lips:': '\u{1F444}',
65
+ ':rocket:': '\u{1F680}',
66
+ ':tada:': '\u{1F389}',
67
+ ':confetti:': '\u{1F38A}',
68
+ ':balloon:': '\u{1F388}',
69
+ ':gift:': '\u{1F381}',
70
+ ':trophy:': '\u{1F3C6}',
71
+ ':medal:': '\u{1F3C5}',
72
+ ':crown:': '\u{1F451}',
73
+ ':gem:': '\u{1F48E}',
74
+ ':bell:': '\u{1F514}',
75
+ ':check:': '\u{2705}',
76
+ ':x:': '\u{274C}',
77
+ ':warning:': '\u{26A0}\u{FE0F}',
78
+ ':no_entry:': '\u{26D4}',
79
+ ':question:': '\u{2753}',
80
+ ':exclamation:': '\u{2757}',
81
+ ':bulb:': '\u{1F4A1}',
82
+ ':book:': '\u{1F4D6}',
83
+ ':memo:': '\u{1F4DD}',
84
+ ':pencil:': '\u{270F}\u{FE0F}',
85
+ ':calendar:': '\u{1F4C5}',
86
+ ':clock:': '\u{1F550}',
87
+ ':hourglass:': '\u{231B}',
88
+ ':lock:': '\u{1F512}',
89
+ ':key:': '\u{1F511}',
90
+ ':hammer:': '\u{1F528}',
91
+ ':wrench:': '\u{1F527}',
92
+ ':link:': '\u{1F517}',
93
+ ':paperclip:': '\u{1F4CE}',
94
+ ':scissors:': '\u{2702}\u{FE0F}',
95
+ ':package:': '\u{1F4E6}',
96
+ ':email:': '\u{1F4E7}',
97
+ ':phone:': '\u{1F4DE}',
98
+ ':computer:': '\u{1F4BB}',
99
+ ':house:': '\u{1F3E0}',
100
+ ':tree:': '\u{1F333}',
101
+ ':sun:': '\u{2600}\u{FE0F}',
102
+ ':moon:': '\u{1F319}',
103
+ ':cloud:': '\u{2601}\u{FE0F}',
104
+ ':rain:': '\u{1F327}\u{FE0F}',
105
+ ':snow:': '\u{2744}\u{FE0F}',
106
+ ':zap:': '\u{26A1}',
107
+ ':rainbow:': '\u{1F308}',
108
+ ':pizza:': '\u{1F355}',
109
+ ':hamburger:': '\u{1F354}',
110
+ ':coffee:': '\u{2615}',
111
+ ':beer:': '\u{1F37A}',
112
+ ':wine:': '\u{1F377}',
113
+ ':cake:': '\u{1F370}',
114
+ ':dog:': '\u{1F436}',
115
+ ':cat:': '\u{1F431}',
116
+ ':poop:': '\u{1F4A9}',
117
+ ':ghost:': '\u{1F47B}',
118
+ ':skull:': '\u{1F480}',
119
+ ':alien:': '\u{1F47D}',
120
+ ':robot:': '\u{1F916}',
121
+ ':handshake:': '\u{1F91D}',
122
+ ':pray2:': '\u{1F64F}',
123
+ ':salute:': '\u{1FAE1}',
124
+ }
125
+
126
+ // ---------------------------------------------------------------------------
127
+ // Detection and search
128
+ // ---------------------------------------------------------------------------
129
+
130
+ /**
131
+ * Detect if a text ends with a completed emoji shortcode like `:smile:`.
132
+ * Returns the shortcode and its unicode value if found, null otherwise.
133
+ */
134
+ export function detectEmojiShortcode(
135
+ text: string,
136
+ ): { shortcode: string; unicode: string } | null {
137
+ // Look for a pattern like :word: at the end of text
138
+ const match = text.match(/:([a-z0-9_]+):$/)
139
+ if (!match) return null
140
+
141
+ const shortcode = `:${match[1]}:`
142
+ const unicode = EMOJI_MAP[shortcode]
143
+ if (!unicode) return null
144
+
145
+ return { shortcode, unicode }
146
+ }
147
+
148
+ /**
149
+ * Search emoji by partial query (matches against shortcode names).
150
+ */
151
+ export function searchEmoji(
152
+ query: string,
153
+ ): { shortcode: string; unicode: string }[] {
154
+ const q = query.toLowerCase().replace(/^:/, '').replace(/:$/, '')
155
+ if (q === '') {
156
+ return Object.entries(EMOJI_MAP).map(([shortcode, unicode]) => ({ shortcode, unicode }))
157
+ }
158
+
159
+ return Object.entries(EMOJI_MAP)
160
+ .filter(([shortcode]) => {
161
+ const name = shortcode.slice(1, -1) // remove colons
162
+ return name.includes(q)
163
+ })
164
+ .map(([shortcode, unicode]) => ({ shortcode, unicode }))
165
+ .sort((a, b) => {
166
+ const aName = a.shortcode.slice(1, -1)
167
+ const bName = b.shortcode.slice(1, -1)
168
+ // Exact start match first
169
+ const aStarts = aName.startsWith(q)
170
+ const bStarts = bName.startsWith(q)
171
+ if (aStarts && !bStarts) return -1
172
+ if (!aStarts && bStarts) return 1
173
+ return aName.localeCompare(bName)
174
+ })
175
+ }
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Undo/Redo history manager.
3
+ * Stores snapshots of editor state for undo/redo operations.
4
+ */
5
+
6
+ import type { EditorState } from './operations.js'
7
+
8
+ // ---------------------------------------------------------------------------
9
+ // Types
10
+ // ---------------------------------------------------------------------------
11
+
12
+ export interface HistoryManager {
13
+ push(state: EditorState): void
14
+ undo(): EditorState | null
15
+ redo(): EditorState | null
16
+ canUndo(): boolean
17
+ canRedo(): boolean
18
+ clear(): void
19
+ size(): number
20
+ }
21
+
22
+ // ---------------------------------------------------------------------------
23
+ // Factory
24
+ // ---------------------------------------------------------------------------
25
+
26
+ const DEFAULT_MAX_SIZE = 100
27
+
28
+ export function createHistory(maxSize: number = DEFAULT_MAX_SIZE): HistoryManager {
29
+ let undoStack: EditorState[] = []
30
+ let redoStack: EditorState[] = []
31
+
32
+ return {
33
+ push(state: EditorState): void {
34
+ // Deep clone to prevent mutation
35
+ const snapshot = JSON.parse(JSON.stringify(state)) as EditorState
36
+ undoStack.push(snapshot)
37
+
38
+ // Enforce max size
39
+ if (undoStack.length > maxSize) {
40
+ undoStack = undoStack.slice(undoStack.length - maxSize)
41
+ }
42
+
43
+ // New edit clears the redo stack
44
+ redoStack = []
45
+ },
46
+
47
+ undo(): EditorState | null {
48
+ if (undoStack.length === 0) return null
49
+ const state = undoStack.pop()!
50
+ redoStack.push(state)
51
+ if (undoStack.length === 0) return state
52
+ return JSON.parse(JSON.stringify(undoStack[undoStack.length - 1])) as EditorState
53
+ },
54
+
55
+ redo(): EditorState | null {
56
+ if (redoStack.length === 0) return null
57
+ const state = redoStack.pop()!
58
+ undoStack.push(state)
59
+ return JSON.parse(JSON.stringify(state)) as EditorState
60
+ },
61
+
62
+ canUndo(): boolean {
63
+ return undoStack.length > 0
64
+ },
65
+
66
+ canRedo(): boolean {
67
+ return redoStack.length > 0
68
+ },
69
+
70
+ clear(): void {
71
+ undoStack = []
72
+ redoStack = []
73
+ },
74
+
75
+ size(): number {
76
+ return undoStack.length
77
+ },
78
+ }
79
+ }
@@ -0,0 +1,106 @@
1
+ // Model
2
+ export type {
3
+ BlockType,
4
+ HeadingLevel,
5
+ MarkType,
6
+ Mark,
7
+ TextSegment,
8
+ MentionSegment,
9
+ EmojiSegment,
10
+ InlineContent,
11
+ Block,
12
+ Document,
13
+ } from './model.js'
14
+
15
+ export {
16
+ generateBlockId,
17
+ resetBlockIdCounter,
18
+ createTextSegment,
19
+ createMentionSegment,
20
+ createEmojiSegment,
21
+ createBlock,
22
+ createDocument,
23
+ getBlockTextLength,
24
+ getBlockText,
25
+ findBlockById,
26
+ findBlockIndex,
27
+ cloneDocument,
28
+ cloneBlock,
29
+ marksEqual,
30
+ normalizeContent,
31
+ } from './model.js'
32
+
33
+ // Selection
34
+ export type { Position, Selection } from './selection.js'
35
+
36
+ export {
37
+ createPosition,
38
+ createSelection,
39
+ createCollapsedSelection,
40
+ isCollapsed,
41
+ isForward,
42
+ getSelectionStart,
43
+ getSelectionEnd,
44
+ getSelectedText,
45
+ getSelectedBlocks,
46
+ clampSelection,
47
+ selectionAtDocStart,
48
+ selectionAtDocEnd,
49
+ selectAll,
50
+ } from './selection.js'
51
+
52
+ // Operations
53
+ export type { EditorState } from './operations.js'
54
+
55
+ export {
56
+ insertText,
57
+ deleteBackward,
58
+ deleteForward,
59
+ deleteSelection,
60
+ insertBlock,
61
+ splitBlock,
62
+ mergeBlockBackward,
63
+ mergeBlockForward,
64
+ changeBlockType,
65
+ indentBlock,
66
+ outdentBlock,
67
+ getActiveMarks,
68
+ toggleMark,
69
+ addMark,
70
+ removeMark,
71
+ moveLeft,
72
+ moveRight,
73
+ moveUp,
74
+ moveDown,
75
+ moveToStartOfBlock,
76
+ moveToEndOfBlock,
77
+ moveToStartOfDocument,
78
+ moveToEndOfDocument,
79
+ expandSelectionWord,
80
+ insertInlineContent,
81
+ } from './operations.js'
82
+
83
+ // Markdown shortcuts
84
+ export { processMarkdownShortcut } from './markdown-shortcuts.js'
85
+
86
+ // Slash commands
87
+ export type { SlashCommand, SlashCommandMenu } from './slash-commands.js'
88
+ export { BUILT_IN_COMMANDS, createSlashCommandMenu, detectSlashTrigger } from './slash-commands.js'
89
+
90
+ // Mentions
91
+ export type { MentionOption, MentionMenu } from './mentions.js'
92
+ export { createMentionMenu, detectMentionTrigger } from './mentions.js'
93
+
94
+ // Emoji
95
+ export { EMOJI_MAP, detectEmojiShortcode, searchEmoji } from './emoji.js'
96
+
97
+ // History
98
+ export type { HistoryManager } from './history.js'
99
+ export { createHistory } from './history.js'
100
+
101
+ // Serialization
102
+ export { toMarkdown, fromMarkdown, toHTML, fromHTML, toPlainText } from './serialization.js'
103
+
104
+ // Editor
105
+ export type { EditorConfig, EditorAPI } from './editor.js'
106
+ export { createEditor } from './editor.js'