@sutrata/editor 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 (337) hide show
  1. package/LICENSE +674 -0
  2. package/dist/ai/OnboardingDialog.d.ts +6 -0
  3. package/dist/ai/OnboardingDialog.js +115 -0
  4. package/dist/ai/VoiceConfirmDialog.d.ts +9 -0
  5. package/dist/ai/VoiceConfirmDialog.js +37 -0
  6. package/dist/ai/VoiceToolbar.d.ts +2 -0
  7. package/dist/ai/VoiceToolbar.js +177 -0
  8. package/dist/ai/ai-client.d.ts +71 -0
  9. package/dist/ai/ai-client.js +494 -0
  10. package/dist/ai/commands.d.ts +12 -0
  11. package/dist/ai/commands.js +140 -0
  12. package/dist/ai/generated-providers.json +3696 -0
  13. package/dist/ai/prompts.d.ts +25 -0
  14. package/dist/ai/prompts.js +59 -0
  15. package/dist/ai/voice-service.d.ts +15 -0
  16. package/dist/ai/voice-service.js +81 -0
  17. package/dist/autocomplete/AutocompletePlugin.d.ts +2 -0
  18. package/dist/autocomplete/AutocompletePlugin.js +19 -0
  19. package/dist/autocomplete/suggestions.d.ts +25 -0
  20. package/dist/autocomplete/suggestions.js +126 -0
  21. package/dist/context/DocumentContext.d.ts +68 -0
  22. package/dist/context/DocumentContext.js +605 -0
  23. package/dist/desktop-api.d.ts +40 -0
  24. package/dist/editor/EditorView.d.ts +2 -0
  25. package/dist/editor/EditorView.js +78 -0
  26. package/dist/editor/SelectionMenu.d.ts +2 -0
  27. package/dist/editor/SelectionMenu.js +102 -0
  28. package/dist/editor/attr-pencil-plugin.d.ts +17 -0
  29. package/dist/editor/attr-pencil-plugin.js +158 -0
  30. package/dist/editor/character-decoration-plugin.d.ts +26 -0
  31. package/dist/editor/character-decoration-plugin.js +77 -0
  32. package/dist/editor/character-view.d.ts +35 -0
  33. package/dist/editor/character-view.js +112 -0
  34. package/dist/editor/editor-bus.d.ts +14 -0
  35. package/dist/editor/editor-bus.js +39 -0
  36. package/dist/editor/find-highlight-plugin.d.ts +7 -0
  37. package/dist/editor/find-highlight-plugin.js +57 -0
  38. package/dist/editor/frontmatter-field-view.d.ts +10 -0
  39. package/dist/editor/frontmatter-field-view.js +48 -0
  40. package/dist/editor/frontmatter-field.d.ts +21 -0
  41. package/dist/editor/frontmatter-field.js +116 -0
  42. package/dist/editor/grapheme-cursor.d.ts +10 -0
  43. package/dist/editor/grapheme-cursor.js +104 -0
  44. package/dist/editor/ime-plugin.d.ts +18 -0
  45. package/dist/editor/ime-plugin.js +71 -0
  46. package/dist/editor/insert-helper.d.ts +1 -0
  47. package/dist/editor/insert-helper.js +42 -0
  48. package/dist/editor/keymap.d.ts +3 -0
  49. package/dist/editor/keymap.js +131 -0
  50. package/dist/editor/language-class-plugin.d.ts +7 -0
  51. package/dist/editor/language-class-plugin.js +75 -0
  52. package/dist/editor/plugins.d.ts +1 -0
  53. package/dist/editor/plugins.js +25 -0
  54. package/dist/editor/prosemirror-to-sutra.d.ts +2 -0
  55. package/dist/editor/prosemirror-to-sutra.js +208 -0
  56. package/dist/editor/scene-heading-view.d.ts +27 -0
  57. package/dist/editor/scene-heading-view.js +136 -0
  58. package/dist/editor/schema.d.ts +3 -0
  59. package/dist/editor/schema.js +135 -0
  60. package/dist/editor/sutra-to-prosemirror.d.ts +3 -0
  61. package/dist/editor/sutra-to-prosemirror.js +154 -0
  62. package/dist/editor/transliterate-input.d.ts +10 -0
  63. package/dist/editor/transliterate-input.js +88 -0
  64. package/dist/extensions/storage-adapter.d.ts +59 -0
  65. package/dist/extensions/storage-adapter.js +9 -0
  66. package/dist/extensions/types.d.ts +73 -0
  67. package/dist/extensions/types.js +12 -0
  68. package/dist/file/docx-exporter.d.ts +8 -0
  69. package/dist/file/docx-exporter.js +494 -0
  70. package/dist/file/docx-importer.d.ts +10 -0
  71. package/dist/file/docx-importer.js +283 -0
  72. package/dist/file/print-paginator.d.ts +29 -0
  73. package/dist/file/print-paginator.js +289 -0
  74. package/dist/file/templates.d.ts +2 -0
  75. package/dist/file/templates.js +66 -0
  76. package/dist/file/workflow-reports.d.ts +34 -0
  77. package/dist/file/workflow-reports.js +719 -0
  78. package/dist/findreplace/FindReplace.d.ts +2 -0
  79. package/dist/findreplace/FindReplace.js +164 -0
  80. package/dist/findreplace/find-engine.d.ts +29 -0
  81. package/dist/findreplace/find-engine.js +69 -0
  82. package/dist/findreplace/scroll-to-match.d.ts +29 -0
  83. package/dist/findreplace/scroll-to-match.js +74 -0
  84. package/dist/fonts/tofu-detect.d.ts +1 -0
  85. package/dist/fonts/tofu-detect.js +48 -0
  86. package/dist/i18n/LanguageContext.d.ts +10 -0
  87. package/dist/i18n/LanguageContext.js +174 -0
  88. package/dist/i18n/language-detect.d.ts +1 -0
  89. package/dist/i18n/language-detect.js +58 -0
  90. package/dist/i18n/useTranslation.d.ts +11 -0
  91. package/dist/i18n/useTranslation.js +60 -0
  92. package/dist/index.d.ts +11 -0
  93. package/dist/index.js +5 -0
  94. package/dist/locales/bn.json +143 -0
  95. package/dist/locales/en.json +143 -0
  96. package/dist/locales/gu.json +143 -0
  97. package/dist/locales/hi.json +143 -0
  98. package/dist/locales/kn.json +143 -0
  99. package/dist/locales/ml.json +143 -0
  100. package/dist/locales/mr.json +143 -0
  101. package/dist/locales/or.json +143 -0
  102. package/dist/locales/pa.json +143 -0
  103. package/dist/locales/si.json +143 -0
  104. package/dist/locales/ta.json +143 -0
  105. package/dist/locales/te.json +143 -0
  106. package/dist/navigator/SceneNavigator.d.ts +2 -0
  107. package/dist/navigator/SceneNavigator.js +612 -0
  108. package/dist/navigator/StatisticsDialog.d.ts +6 -0
  109. package/dist/navigator/StatisticsDialog.js +146 -0
  110. package/dist/navigator/scene-list.d.ts +16 -0
  111. package/dist/navigator/scene-list.js +70 -0
  112. package/dist/settings/SettingsDialog.d.ts +6 -0
  113. package/dist/settings/SettingsDialog.js +147 -0
  114. package/dist/shell/AppBar.d.ts +2 -0
  115. package/dist/shell/AppBar.js +34 -0
  116. package/dist/shell/AppShell.d.ts +2 -0
  117. package/dist/shell/AppShell.js +30 -0
  118. package/dist/shell/ConfirmDialog.d.ts +16 -0
  119. package/dist/shell/ConfirmDialog.js +23 -0
  120. package/dist/shell/ElementToolbar.d.ts +2 -0
  121. package/dist/shell/ElementToolbar.js +30 -0
  122. package/dist/shell/LanguageStatus.d.ts +2 -0
  123. package/dist/shell/LanguageStatus.js +65 -0
  124. package/dist/shell/StatusBar.d.ts +2 -0
  125. package/dist/shell/StatusBar.js +54 -0
  126. package/dist/shell/SutrataLogo.d.ts +8 -0
  127. package/dist/shell/SutrataLogo.js +7 -0
  128. package/dist/shell/Toast.d.ts +12 -0
  129. package/dist/shell/Toast.js +21 -0
  130. package/dist/shell/ToolbarButton.d.ts +11 -0
  131. package/dist/shell/ToolbarButton.js +4 -0
  132. package/dist/shell/VersionHistory.d.ts +12 -0
  133. package/dist/shell/VersionHistory.js +89 -0
  134. package/dist/shell/Watermark.d.ts +3 -0
  135. package/dist/shell/Watermark.js +10 -0
  136. package/dist/shell/fonts/fonts.css +1133 -0
  137. package/dist/shell/icons.d.ts +45 -0
  138. package/dist/shell/icons.js +51 -0
  139. package/dist/shell/toolbar-actions.d.ts +6 -0
  140. package/dist/shell/toolbar-actions.js +58 -0
  141. package/dist/source/SourceView.d.ts +1 -0
  142. package/dist/source/SourceView.js +106 -0
  143. package/dist/source/find-highlight-source.d.ts +14 -0
  144. package/dist/source/find-highlight-source.js +47 -0
  145. package/dist/source/sutra-lang.d.ts +2 -0
  146. package/dist/source/sutra-lang.js +97 -0
  147. package/dist/spellcheck/dictionaries.d.ts +9 -0
  148. package/dist/spellcheck/dictionaries.js +16 -0
  149. package/dist/spellcheck/hunspell.d.ts +23 -0
  150. package/dist/spellcheck/hunspell.js +94 -0
  151. package/dist/spellcheck/spellcheck-plugin.d.ts +18 -0
  152. package/dist/spellcheck/spellcheck-plugin.js +75 -0
  153. package/dist/styles/StyleDialog.d.ts +6 -0
  154. package/dist/styles/StyleDialog.js +63 -0
  155. package/dist/styles/builtin-styles.d.ts +43 -0
  156. package/dist/styles/builtin-styles.js +131 -0
  157. package/dist/styles/css-adapter.d.ts +32 -0
  158. package/dist/styles/css-adapter.js +71 -0
  159. package/dist/styles/docx-adapter.d.ts +7 -0
  160. package/dist/styles/docx-adapter.js +84 -0
  161. package/dist/styles/embed-fonts.d.ts +20 -0
  162. package/dist/styles/embed-fonts.js +81 -0
  163. package/dist/styles/pagination.d.ts +19 -0
  164. package/dist/styles/pagination.js +22 -0
  165. package/dist/styles/print-adapter.d.ts +6 -0
  166. package/dist/styles/print-adapter.js +288 -0
  167. package/dist/styles/registry.d.ts +6 -0
  168. package/dist/styles/registry.js +14 -0
  169. package/dist/styles/screenplay.css +3006 -0
  170. package/dist/styles/script-ranges.d.ts +6 -0
  171. package/dist/styles/script-ranges.js +17 -0
  172. package/dist/styles/types.d.ts +93 -0
  173. package/dist/styles/types.js +18 -0
  174. package/dist/styles/validate.d.ts +12 -0
  175. package/dist/styles/validate.js +105 -0
  176. package/dist/templates/templates.d.ts +10 -0
  177. package/dist/templates/templates.js +181 -0
  178. package/dist/titlepage/ExportDialog.d.ts +1 -0
  179. package/dist/titlepage/ExportDialog.js +152 -0
  180. package/dist/titlepage/TitlePageDialog.d.ts +6 -0
  181. package/dist/titlepage/TitlePageDialog.js +96 -0
  182. package/dist/titlepage/frontmatter-form.d.ts +56 -0
  183. package/dist/titlepage/frontmatter-form.js +245 -0
  184. package/dist/titlepage/languages.d.ts +10 -0
  185. package/dist/titlepage/languages.js +31 -0
  186. package/dist/types.d.ts +6 -0
  187. package/dist/types.js +1 -0
  188. package/package.json +47 -0
  189. package/scripts/copy-assets.mjs +16 -0
  190. package/scripts/generate-providers.mjs +127 -0
  191. package/src/ai/OnboardingDialog.tsx +390 -0
  192. package/src/ai/VoiceConfirmDialog.tsx +137 -0
  193. package/src/ai/VoiceToolbar.tsx +321 -0
  194. package/src/ai/ai-client.ts +596 -0
  195. package/src/ai/commands.ts +164 -0
  196. package/src/ai/generated-providers.json +3696 -0
  197. package/src/ai/prompts.ts +62 -0
  198. package/src/ai/voice-service.ts +96 -0
  199. package/src/autocomplete/AutocompletePlugin.ts +21 -0
  200. package/src/autocomplete/suggestions.ts +147 -0
  201. package/src/context/DocumentContext.tsx +648 -0
  202. package/src/desktop-api.d.ts +40 -0
  203. package/src/editor/EditorView.tsx +82 -0
  204. package/src/editor/SelectionMenu.tsx +152 -0
  205. package/src/editor/attr-pencil-plugin.ts +172 -0
  206. package/src/editor/character-decoration-plugin.ts +104 -0
  207. package/src/editor/editor-bus.ts +51 -0
  208. package/src/editor/find-highlight-plugin.ts +68 -0
  209. package/src/editor/frontmatter-field-view.ts +52 -0
  210. package/src/editor/frontmatter-field.ts +115 -0
  211. package/src/editor/grapheme-cursor.ts +99 -0
  212. package/src/editor/ime-plugin.ts +85 -0
  213. package/src/editor/insert-helper.ts +43 -0
  214. package/src/editor/keymap.ts +124 -0
  215. package/src/editor/language-class-plugin.ts +91 -0
  216. package/src/editor/plugins.ts +26 -0
  217. package/src/editor/prosemirror-to-sutra.ts +192 -0
  218. package/src/editor/scene-heading-view.ts +147 -0
  219. package/src/editor/schema.ts +156 -0
  220. package/src/editor/sutra-to-prosemirror.ts +156 -0
  221. package/src/extensions/storage-adapter.ts +65 -0
  222. package/src/extensions/types.ts +60 -0
  223. package/src/file/docx-exporter.ts +585 -0
  224. package/src/file/docx-importer.ts +313 -0
  225. package/src/file/print-paginator.ts +301 -0
  226. package/src/file/templates.ts +73 -0
  227. package/src/file/workflow-reports.ts +820 -0
  228. package/src/findreplace/FindReplace.tsx +242 -0
  229. package/src/findreplace/find-engine.ts +97 -0
  230. package/src/findreplace/scroll-to-match.ts +89 -0
  231. package/src/fonts/tofu-detect.ts +53 -0
  232. package/src/i18n/LanguageContext.tsx +207 -0
  233. package/src/i18n/language-detect.ts +73 -0
  234. package/src/i18n/useTranslation.tsx +74 -0
  235. package/src/index.ts +27 -0
  236. package/src/locales/bn.json +143 -0
  237. package/src/locales/en.json +143 -0
  238. package/src/locales/gu.json +143 -0
  239. package/src/locales/hi.json +143 -0
  240. package/src/locales/kn.json +143 -0
  241. package/src/locales/ml.json +143 -0
  242. package/src/locales/mr.json +143 -0
  243. package/src/locales/or.json +143 -0
  244. package/src/locales/pa.json +143 -0
  245. package/src/locales/si.json +143 -0
  246. package/src/locales/ta.json +143 -0
  247. package/src/locales/te.json +143 -0
  248. package/src/navigator/SceneNavigator.tsx +844 -0
  249. package/src/navigator/StatisticsDialog.tsx +249 -0
  250. package/src/navigator/scene-list.ts +84 -0
  251. package/src/settings/SettingsDialog.tsx +303 -0
  252. package/src/shell/AppBar.tsx +354 -0
  253. package/src/shell/AppShell.tsx +71 -0
  254. package/src/shell/ConfirmDialog.tsx +71 -0
  255. package/src/shell/ElementToolbar.tsx +175 -0
  256. package/src/shell/LanguageStatus.tsx +101 -0
  257. package/src/shell/StatusBar.tsx +135 -0
  258. package/src/shell/SutrataLogo.tsx +89 -0
  259. package/src/shell/Toast.tsx +46 -0
  260. package/src/shell/ToolbarButton.tsx +30 -0
  261. package/src/shell/VersionHistory.tsx +212 -0
  262. package/src/shell/Watermark.tsx +9 -0
  263. package/src/shell/fonts/fonts.css +1133 -0
  264. package/src/shell/icons.tsx +335 -0
  265. package/src/shell/toolbar-actions.ts +59 -0
  266. package/src/source/SourceView.tsx +111 -0
  267. package/src/source/find-highlight-source.ts +57 -0
  268. package/src/source/sutra-lang.ts +121 -0
  269. package/src/spellcheck/dictionaries.ts +21 -0
  270. package/src/spellcheck/hunspell.ts +110 -0
  271. package/src/spellcheck/spellcheck-plugin.ts +83 -0
  272. package/src/styles/StyleDialog.tsx +148 -0
  273. package/src/styles/builtin-styles.ts +139 -0
  274. package/src/styles/css-adapter.ts +76 -0
  275. package/src/styles/docx-adapter.ts +109 -0
  276. package/src/styles/embed-fonts.ts +81 -0
  277. package/src/styles/pagination.ts +27 -0
  278. package/src/styles/print-adapter.ts +288 -0
  279. package/src/styles/registry.ts +20 -0
  280. package/src/styles/screenplay.css +3006 -0
  281. package/src/styles/script-ranges.ts +17 -0
  282. package/src/styles/types.ts +104 -0
  283. package/src/styles/validate.ts +114 -0
  284. package/src/templates/templates.ts +194 -0
  285. package/src/titlepage/ExportDialog.tsx +494 -0
  286. package/src/titlepage/TitlePageDialog.tsx +312 -0
  287. package/src/titlepage/frontmatter-form.ts +280 -0
  288. package/src/titlepage/languages.ts +37 -0
  289. package/src/types.ts +7 -0
  290. package/tests/AppBar.test.tsx +35 -0
  291. package/tests/AppShell.test.tsx +22 -0
  292. package/tests/ElementToolbar.test.tsx +36 -0
  293. package/tests/LanguageStatus.test.tsx +129 -0
  294. package/tests/SelectionMenu.test.tsx +71 -0
  295. package/tests/ToolbarButton.test.tsx +24 -0
  296. package/tests/ai-onboarding.test.ts +102 -0
  297. package/tests/ai-status.test.tsx +72 -0
  298. package/tests/ai-structured.test.ts +94 -0
  299. package/tests/autocomplete/AutocompletePlugin.test.ts +20 -0
  300. package/tests/autocomplete/suggestions.test.ts +106 -0
  301. package/tests/document-context.test.tsx +565 -0
  302. package/tests/docx-importer.test.ts +160 -0
  303. package/tests/editor/character-decoration-plugin.test.ts +101 -0
  304. package/tests/editor/character-extension.test.ts +44 -0
  305. package/tests/editor/grapheme-cursor.test.ts +118 -0
  306. package/tests/editor/ime-plugin.test.ts +72 -0
  307. package/tests/editor/inline-note-bridge.test.ts +32 -0
  308. package/tests/editor/language-class-plugin.test.ts +265 -0
  309. package/tests/editor/title-page.test.ts +124 -0
  310. package/tests/embed-fonts.test.ts +17 -0
  311. package/tests/exporters.test.ts +365 -0
  312. package/tests/findreplace/FindReplace.test.tsx +391 -0
  313. package/tests/findreplace/find-engine.test.ts +86 -0
  314. package/tests/findreplace/scroll-to-match.test.ts +50 -0
  315. package/tests/fonts/tofu-detect.test.ts +122 -0
  316. package/tests/i18n/LanguageContext.test.tsx +146 -0
  317. package/tests/i18n/language-detect.test.ts +54 -0
  318. package/tests/i18n/locale-parity.test.ts +25 -0
  319. package/tests/i18n/useTranslation.test.tsx +45 -0
  320. package/tests/keymap.test.ts +18 -0
  321. package/tests/navigator/SceneNavigator.test.tsx +177 -0
  322. package/tests/navigator/StatisticsDialog.test.tsx +63 -0
  323. package/tests/navigator/scene-list.test.ts +71 -0
  324. package/tests/print-paginator.test.ts +82 -0
  325. package/tests/shell/VersionHistory.test.tsx +129 -0
  326. package/tests/spellcheck/hunspell.test.ts +82 -0
  327. package/tests/spellcheck/spellcheck-plugin.test.ts +56 -0
  328. package/tests/styles.test.ts +315 -0
  329. package/tests/templates/templates.test.ts +83 -0
  330. package/tests/titlepage/TitlePageDialog.test.tsx +90 -0
  331. package/tests/titlepage/apply-title-page.test.ts +61 -0
  332. package/tests/titlepage/frontmatter-form.test.ts +115 -0
  333. package/tests/toolbar-actions.test.ts +93 -0
  334. package/tests/voice-commands.test.ts +58 -0
  335. package/tsconfig.json +17 -0
  336. package/vitest.config.ts +11 -0
  337. package/vitest.setup.ts +65 -0
@@ -0,0 +1,45 @@
1
+ import React from 'react';
2
+ type IconProps = {
3
+ size?: number;
4
+ };
5
+ export declare const NavigatorIcon: ({ size }: IconProps) => React.JSX.Element;
6
+ export declare const TitlePageIcon: ({ size }: IconProps) => React.JSX.Element;
7
+ export declare const NewIcon: ({ size }: IconProps) => React.JSX.Element;
8
+ export declare const OpenIcon: ({ size }: IconProps) => React.JSX.Element;
9
+ export declare const ImportDocxIcon: ({ size }: IconProps) => React.JSX.Element;
10
+ export declare const StyleIcon: ({ size }: IconProps) => React.JSX.Element;
11
+ export declare const SaveIcon: ({ size }: IconProps) => React.JSX.Element;
12
+ export declare const SaveAsIcon: ({ size }: IconProps) => React.JSX.Element;
13
+ export declare const UndoIcon: ({ size }: IconProps) => React.JSX.Element;
14
+ export declare const RedoIcon: ({ size }: IconProps) => React.JSX.Element;
15
+ export declare const SceneIcon: ({ size }: IconProps) => React.JSX.Element;
16
+ export declare const ActionIcon: ({ size }: IconProps) => React.JSX.Element;
17
+ export declare const CharacterIcon: ({ size }: IconProps) => React.JSX.Element;
18
+ export declare const DialogueIcon: ({ size }: IconProps) => React.JSX.Element;
19
+ export declare const ParentheticalIcon: ({ size }: IconProps) => React.JSX.Element;
20
+ export declare const TransitionIcon: ({ size }: IconProps) => React.JSX.Element;
21
+ export declare const CenteredIcon: ({ size }: IconProps) => React.JSX.Element;
22
+ export declare const LyricsIcon: ({ size }: IconProps) => React.JSX.Element;
23
+ export declare const NoteIcon: ({ size }: IconProps) => React.JSX.Element;
24
+ export declare const PageBreakIcon: ({ size }: IconProps) => React.JSX.Element;
25
+ export declare const SectionIcon: ({ size }: IconProps) => React.JSX.Element;
26
+ export declare const BoldIcon: ({ size }: IconProps) => React.JSX.Element;
27
+ export declare const ItalicIcon: ({ size }: IconProps) => React.JSX.Element;
28
+ export declare const UnderlineIcon: ({ size }: IconProps) => React.JSX.Element;
29
+ export declare const SourceIcon: ({ size }: IconProps) => React.JSX.Element;
30
+ export declare const FormattedIcon: ({ size }: IconProps) => React.JSX.Element;
31
+ export declare const RibbonIcon: ({ size }: IconProps) => React.JSX.Element;
32
+ export declare const ExportIcon: ({ size }: IconProps) => React.JSX.Element;
33
+ export declare const SettingsIcon: ({ size }: IconProps) => React.JSX.Element;
34
+ export declare const OverflowIcon: ({ size }: IconProps) => React.JSX.Element;
35
+ export declare const EyeIcon: ({ size }: IconProps) => React.JSX.Element;
36
+ export declare const EyeOffIcon: ({ size }: IconProps) => React.JSX.Element;
37
+ export declare const LockIcon: ({ size }: IconProps) => React.JSX.Element;
38
+ export declare const StatsIcon: ({ size }: IconProps) => React.JSX.Element;
39
+ export declare const HistoryIcon: ({ size }: IconProps) => React.JSX.Element;
40
+ export declare const MicIcon: ({ size }: IconProps) => React.JSX.Element;
41
+ export declare const SparklesIcon: ({ size }: IconProps) => React.JSX.Element;
42
+ export declare const ClockIcon: ({ size }: IconProps) => React.JSX.Element;
43
+ export declare const MenuIcon: ({ size }: IconProps) => React.JSX.Element;
44
+ export declare const CloseIcon: ({ size }: IconProps) => React.JSX.Element;
45
+ export {};
@@ -0,0 +1,51 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ const base = (size = 16) => ({
3
+ width: size,
4
+ height: size,
5
+ viewBox: '0 0 16 16',
6
+ fill: 'none',
7
+ stroke: 'currentColor',
8
+ strokeWidth: 1.35,
9
+ strokeLinecap: 'round',
10
+ strokeLinejoin: 'round',
11
+ });
12
+ export const NavigatorIcon = ({ size }) => (_jsxs("svg", { ...base(size), children: [_jsx("rect", { x: "1.5", y: "2", width: "13", height: "12", rx: "1.5" }), _jsx("line", { x1: "5.5", y1: "2", x2: "5.5", y2: "14" })] }));
13
+ export const TitlePageIcon = ({ size }) => (_jsxs("svg", { ...base(size), children: [_jsx("path", { d: "M3 1.5h6l4 4V13.5a1 1 0 01-1 1H3a1 1 0 01-1-1v-11a1 1 0 011-1z" }), _jsx("polyline", { points: "9 1.5 9 5.5 13 5.5" }), _jsx("line", { x1: "5", y1: "8", x2: "11", y2: "8" }), _jsx("line", { x1: "5", y1: "10.5", x2: "9", y2: "10.5" })] }));
14
+ export const NewIcon = ({ size }) => (_jsxs("svg", { ...base(size), children: [_jsx("path", { d: "M3 1.5h6l4 4V13.5a1 1 0 01-1 1H3a1 1 0 01-1-1v-11a1 1 0 011-1z" }), _jsx("polyline", { points: "9 1.5 9 5.5 13 5.5" }), _jsx("line", { x1: "8", y1: "8.5", x2: "8", y2: "12" }), _jsx("line", { x1: "6.25", y1: "10.25", x2: "9.75", y2: "10.25" })] }));
15
+ export const OpenIcon = ({ size }) => (_jsxs("svg", { ...base(size), children: [_jsx("path", { d: "M1.5 3.5a1 1 0 011-1h3.5l1.5 1.5h7a1 1 0 011 1V6H1.5V3.5z" }), _jsx("path", { d: "M1 6.5h14l-1.5 6.5a1 1 0 01-1 .7H3.5a1 1 0 01-1-.7L1 6.5z" })] }));
16
+ export const ImportDocxIcon = ({ size }) => (_jsxs("svg", { ...base(size), children: [_jsx("path", { d: "M3 1.5h6l4 4V13.5a1 1 0 01-1 1H3a1 1 0 01-1-1v-11a1 1 0 011-1z" }), _jsx("polyline", { points: "9 1.5 9 5.5 13 5.5" }), _jsx("line", { x1: "8", y1: "7.5", x2: "8", y2: "11.5" }), _jsx("polyline", { points: "6 9.5 8 11.5 10 9.5" })] }));
17
+ export const StyleIcon = ({ size }) => (_jsxs("svg", { ...base(size), children: [_jsx("path", { d: "M8 2a6 6 0 00-6 6c0 3.3 2.7 6 6 6 1 0 1.8-.8 1.8-1.8 0-.5-.2-.9-.5-1.2-.3-.4-.5-.9-.5-1.5 0-1.1.9-2 2-2h1.2C13.8 7.5 14 6.7 14 5.8 14 3.7 11.3 2 8 2z" }), _jsx("circle", { cx: "5", cy: "6", r: "0.75", fill: "currentColor", stroke: "none" }), _jsx("circle", { cx: "8", cy: "4.8", r: "0.75", fill: "currentColor", stroke: "none" }), _jsx("circle", { cx: "11", cy: "6", r: "0.75", fill: "currentColor", stroke: "none" })] }));
18
+ export const SaveIcon = ({ size }) => (_jsxs("svg", { ...base(size), children: [_jsx("path", { d: "M2.5 2h8.5l2.5 2.5V13.5a1 1 0 01-1 1h-10a1 1 0 01-1-1V3a1 1 0 011-1z" }), _jsx("path", { d: "M5 2v4h5V2" }), _jsx("path", { d: "M4.5 9h7v5h-7z" })] }));
19
+ export const SaveAsIcon = ({ size = 16 }) => (_jsxs("svg", { ...base(size), children: [_jsx("path", { d: "M2.5 2h7.5l2.5 2.5V8" }), _jsx("path", { d: "M5 2v3.5h4V2" }), _jsx("path", { d: "M2.5 13.5a1 1 0 01-1-1V3a1 1 0 011-1" }), _jsx("path", { d: "M1.5 12.5a1 1 0 001 1h5.5" }), _jsx("circle", { cx: "12", cy: "12", r: "3" }), _jsx("line", { x1: "12", y1: "10.5", x2: "12", y2: "13.5" }), _jsx("line", { x1: "10.5", y1: "12", x2: "13.5", y2: "12" })] }));
20
+ export const UndoIcon = ({ size }) => (_jsxs("svg", { ...base(size), children: [_jsx("path", { d: "M2 7c0-2.8 2.2-5 5-5 2.5 0 4.6 1.8 5 4.2" }), _jsx("path", { d: "M2 3v4h4" })] }));
21
+ export const RedoIcon = ({ size }) => (_jsxs("svg", { ...base(size), children: [_jsx("path", { d: "M14 7c0-2.8-2.2-5-5-5C6.5 2 4.4 3.8 4 6.2" }), _jsx("path", { d: "M14 3v4h-4" })] }));
22
+ export const SceneIcon = ({ size }) => (_jsxs("svg", { ...base(size), viewBox: "0 0 18 18", children: [_jsx("line", { x1: "3", y1: "5", x2: "3", y2: "13" }), _jsx("line", { x1: "3", y1: "9", x2: "8", y2: "9" }), _jsx("line", { x1: "8", y1: "5", x2: "8", y2: "13" }), _jsx("line", { x1: "12", y1: "5", x2: "12", y2: "13" }), _jsx("line", { x1: "12", y1: "9", x2: "17", y2: "9" }), _jsx("line", { x1: "17", y1: "5", x2: "17", y2: "13" })] }));
23
+ export const ActionIcon = ({ size }) => (_jsxs("svg", { ...base(size), viewBox: "0 0 18 18", children: [_jsx("line", { x1: "2", y1: "5", x2: "16", y2: "5" }), _jsx("line", { x1: "2", y1: "8", x2: "16", y2: "8" }), _jsx("line", { x1: "2", y1: "11", x2: "12", y2: "11" }), _jsx("line", { x1: "2", y1: "14", x2: "9", y2: "14" })] }));
24
+ export const CharacterIcon = ({ size }) => (_jsxs("svg", { ...base(size), viewBox: "0 0 18 18", children: [_jsx("circle", { cx: "9", cy: "6", r: "3" }), _jsx("path", { d: "M3 16c0-3.3 2.7-6 6-6s6 2.7 6 6" })] }));
25
+ export const DialogueIcon = ({ size }) => (_jsx("svg", { ...base(size), viewBox: "0 0 18 18", children: _jsx("path", { d: "M2 4h14a1 1 0 011 1v6a1 1 0 01-1 1H6l-4 3v-3H2a1 1 0 01-1-1V5a1 1 0 011-1z" }) }));
26
+ export const ParentheticalIcon = ({ size }) => (_jsxs("svg", { ...base(size), viewBox: "0 0 18 18", children: [_jsx("path", { d: "M6 4c-2 2-2 8 0 10" }), _jsx("path", { d: "M12 4c2 2 2 8 0 10" })] }));
27
+ export const TransitionIcon = ({ size }) => (_jsxs("svg", { ...base(size), viewBox: "0 0 18 18", children: [_jsx("polyline", { points: "3,6 8,9 3,12" }), _jsx("polyline", { points: "9,6 14,9 9,12" }), _jsx("line", { x1: "15", y1: "6", x2: "15", y2: "12" })] }));
28
+ export const CenteredIcon = ({ size }) => (_jsxs("svg", { ...base(size), viewBox: "0 0 18 18", children: [_jsx("line", { x1: "3", y1: "5", x2: "15", y2: "5" }), _jsx("line", { x1: "5", y1: "9", x2: "13", y2: "9" }), _jsx("line", { x1: "3", y1: "13", x2: "15", y2: "13" })] }));
29
+ export const LyricsIcon = ({ size }) => (_jsxs("svg", { ...base(size), viewBox: "0 0 18 18", children: [_jsx("circle", { cx: "5", cy: "13", r: "2" }), _jsx("circle", { cx: "13", cy: "11", r: "2" }), _jsx("line", { x1: "7", y1: "13", x2: "7", y2: "4" }), _jsx("line", { x1: "15", y1: "11", x2: "15", y2: "2" }), _jsx("line", { x1: "7", y1: "4", x2: "15", y2: "2" })] }));
30
+ export const NoteIcon = ({ size }) => (_jsxs("svg", { ...base(size), viewBox: "0 0 18 18", children: [_jsx("rect", { x: "2", y: "3", width: "11", height: "12", rx: "1" }), _jsx("line", { x1: "5", y1: "7", x2: "10", y2: "7" }), _jsx("line", { x1: "5", y1: "10", x2: "10", y2: "10" }), _jsx("line", { x1: "5", y1: "13", x2: "8", y2: "13" })] }));
31
+ export const PageBreakIcon = ({ size }) => (_jsxs("svg", { ...base(size), viewBox: "0 0 18 18", children: [_jsx("line", { x1: "2", y1: "9", x2: "16", y2: "9" }), _jsx("line", { x1: "2", y1: "5", x2: "16", y2: "5", strokeDasharray: "2 2", opacity: "0.4" }), _jsx("line", { x1: "2", y1: "13", x2: "16", y2: "13", strokeDasharray: "2 2", opacity: "0.4" })] }));
32
+ export const SectionIcon = ({ size }) => (_jsxs("svg", { ...base(size), viewBox: "0 0 18 18", children: [_jsx("line", { x1: "3", y1: "6", x2: "15", y2: "6" }), _jsx("line", { x1: "3", y1: "9", x2: "15", y2: "9" }), _jsx("line", { x1: "6", y1: "3", x2: "6", y2: "7" }), _jsx("line", { x1: "12", y1: "3", x2: "12", y2: "7" }), _jsx("line", { x1: "6", y1: "8", x2: "6", y2: "12" }), _jsx("line", { x1: "12", y1: "8", x2: "12", y2: "12" })] }));
33
+ export const BoldIcon = ({ size = 16 }) => (_jsx("svg", { width: size, height: size, viewBox: "0 0 16 16", fill: "currentColor", children: _jsx("text", { x: "3", y: "13", fontFamily: "Georgia,serif", fontSize: "13", fontWeight: "700", children: "B" }) }));
34
+ export const ItalicIcon = ({ size = 16 }) => (_jsx("svg", { width: size, height: size, viewBox: "0 0 16 16", fill: "currentColor", children: _jsx("text", { x: "5", y: "13", fontFamily: "Georgia,serif", fontSize: "13", fontStyle: "italic", children: "I" }) }));
35
+ export const UnderlineIcon = ({ size = 16 }) => (_jsxs("svg", { width: size, height: size, viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: 1.3, strokeLinecap: "round", children: [_jsx("text", { x: "4", y: "11", fontFamily: "Georgia,serif", fontSize: "11", fill: "currentColor", stroke: "none", children: "U" }), _jsx("line", { x1: "3", y1: "14", x2: "13", y2: "14" })] }));
36
+ export const SourceIcon = ({ size }) => (_jsxs("svg", { ...base(size), children: [_jsx("polyline", { points: "5,4 2,8 5,12" }), _jsx("polyline", { points: "11,4 14,8 11,12" }), _jsx("line", { x1: "9", y1: "2", x2: "7", y2: "14" })] }));
37
+ export const FormattedIcon = ({ size }) => (_jsxs("svg", { ...base(size), children: [_jsx("line", { x1: "2", y1: "4", x2: "14", y2: "4" }), _jsx("line", { x1: "2", y1: "7", x2: "14", y2: "7" }), _jsx("line", { x1: "2", y1: "10", x2: "9", y2: "10" })] }));
38
+ export const RibbonIcon = ({ size }) => (_jsxs("svg", { ...base(size), children: [_jsx("rect", { x: "1", y: "4", width: "4", height: "4", rx: "0.5" }), _jsx("rect", { x: "6", y: "4", width: "4", height: "4", rx: "0.5" }), _jsx("rect", { x: "11", y: "4", width: "4", height: "4", rx: "0.5" }), _jsx("line", { x1: "1", y1: "11", x2: "15", y2: "11" }), _jsx("line", { x1: "1", y1: "13.5", x2: "10", y2: "13.5" })] }));
39
+ export const ExportIcon = ({ size }) => (_jsxs("svg", { ...base(size), children: [_jsx("path", { d: "M2.5 7.5v5a1 1 0 001 1h9a1 1 0 001-1v-5" }), _jsx("line", { x1: "8", y1: "2", x2: "8", y2: "9.5" }), _jsx("polyline", { points: "4.75 5.25 8 2 11.25 5.25" })] }));
40
+ export const SettingsIcon = ({ size }) => (_jsxs("svg", { ...base(size), children: [_jsx("circle", { cx: "8", cy: "8", r: "2.25" }), _jsx("path", { d: "M6.9 1.8h2.2l.3 1.4a4.8 4.8 0 011.2.7l1.3-.6 1.5 1.5-.6 1.3c.3.4.5.8.7 1.2l1.4.3v2.2l-1.4.3a4.8 4.8 0 01-.7 1.2l.6 1.3-1.5 1.5-1.3-.6a4.8 4.8 0 01-1.2.7l-.3 1.4H6.9l-.3-1.4a4.8 4.8 0 01-1.2-.7l-1.3.6-1.5-1.5.6-1.3a4.8 4.8 0 01-.7-1.2l-1.4-.3V6.9l1.4-.3a4.8 4.8 0 01.7-1.2l-.6-1.3 1.5-1.5 1.3.6a4.8 4.8 0 011.2-.7l.3-1.4z" })] }));
41
+ export const OverflowIcon = ({ size = 14 }) => (_jsxs("svg", { width: size, height: size, viewBox: "0 0 16 16", fill: "currentColor", children: [_jsx("circle", { cx: "3", cy: "8", r: "1.5" }), _jsx("circle", { cx: "8", cy: "8", r: "1.5" }), _jsx("circle", { cx: "13", cy: "8", r: "1.5" })] }));
42
+ export const EyeIcon = ({ size }) => (_jsxs("svg", { ...base(size), children: [_jsx("path", { d: "M1 8s3-6 7-6 7 6 7 6-3 6-7 6-7-6-7-6z" }), _jsx("circle", { cx: "8", cy: "8", r: "2.2" })] }));
43
+ export const EyeOffIcon = ({ size }) => (_jsxs("svg", { ...base(size), children: [_jsx("path", { d: "M1 8s3-6 7-6 7 6 7 6-3 6-7 6-7-6-7-6z" }), _jsx("circle", { cx: "8", cy: "8", r: "2.2" }), _jsx("line", { x1: "2", y1: "2", x2: "14", y2: "14" })] }));
44
+ export const LockIcon = ({ size }) => (_jsxs("svg", { ...base(size), children: [_jsx("rect", { x: "3", y: "7", width: "10", height: "7", rx: "1.5" }), _jsx("path", { d: "M4.5 7V4.5a3.5 3.5 0 017 0V7" })] }));
45
+ export const StatsIcon = ({ size }) => (_jsxs("svg", { ...base(size), children: [_jsx("line", { x1: "12", y1: "14", x2: "12", y2: "4" }), _jsx("line", { x1: "8", y1: "14", x2: "8", y2: "7" }), _jsx("line", { x1: "4", y1: "14", x2: "4", y2: "10" })] }));
46
+ export const HistoryIcon = ({ size }) => (_jsxs("svg", { ...base(size), children: [_jsx("circle", { cx: "8", cy: "8.5", r: "6" }), _jsx("polyline", { points: "8,5.5 8,8.5 10.5,10" })] }));
47
+ export const MicIcon = ({ size }) => (_jsxs("svg", { ...base(size), children: [_jsx("rect", { x: "5.5", y: "2", width: "5", height: "8", rx: "2.5" }), _jsx("path", { d: "M3 7.5a5 5 0 0010 0" }), _jsx("line", { x1: "8", y1: "12.5", x2: "8", y2: "14.5" }), _jsx("line", { x1: "5.5", y1: "14.5", x2: "10.5", y2: "14.5" })] }));
48
+ export const SparklesIcon = ({ size }) => (_jsxs("svg", { ...base(size), children: [_jsx("path", { d: "M8 2l1.2 3.8L13 7l-3.8 1.2L8 12l-1.2-3.8L3 7l3.8-1.2L8 2z" }), _jsx("path", { d: "M12.5 11l.6 1.9 1.9.6-1.9.6-.6 1.9-.6-1.9-1.9-.6 1.9-.6.6-1.9z" })] }));
49
+ export const ClockIcon = ({ size }) => (_jsxs("svg", { ...base(size), children: [_jsx("circle", { cx: "8", cy: "8", r: "6" }), _jsx("polyline", { points: "8 4.5 8 8 10.5 9.5" })] }));
50
+ export const MenuIcon = ({ size }) => (_jsxs("svg", { ...base(size), children: [_jsx("line", { x1: "2.5", y1: "4.5", x2: "13.5", y2: "4.5" }), _jsx("line", { x1: "2.5", y1: "8", x2: "13.5", y2: "8" }), _jsx("line", { x1: "2.5", y1: "11.5", x2: "13.5", y2: "11.5" })] }));
51
+ export const CloseIcon = ({ size }) => (_jsxs("svg", { ...base(size), children: [_jsx("line", { x1: "3.5", y1: "3.5", x2: "12.5", y2: "12.5" }), _jsx("line", { x1: "12.5", y1: "3.5", x2: "3.5", y2: "12.5" })] }));
@@ -0,0 +1,6 @@
1
+ import type { Command } from 'prosemirror-state';
2
+ import { undo, redo } from 'prosemirror-history';
3
+ export declare function makeSetBlock(typeName: string, attrs?: Record<string, unknown>): Command;
4
+ export declare function makeToggleMark(markName: string): Command;
5
+ export declare function makeSetOrToggleNote(): Command;
6
+ export { undo, redo };
@@ -0,0 +1,58 @@
1
+ import { TextSelection } from 'prosemirror-state';
2
+ import { toggleMark } from 'prosemirror-commands';
3
+ import { undo, redo } from 'prosemirror-history';
4
+ import { schema } from '../editor/schema';
5
+ export function makeSetBlock(typeName, attrs = {}) {
6
+ return (state, dispatch) => {
7
+ const nodeType = schema.nodes[typeName];
8
+ if (!nodeType)
9
+ return false;
10
+ if (dispatch) {
11
+ const { from, to } = state.selection;
12
+ const tr = state.tr;
13
+ state.doc.nodesBetween(from, to, (node, pos) => {
14
+ if (node.isBlock && node.type.name !== 'doc') {
15
+ tr.setNodeMarkup(pos, nodeType, { ...node.attrs, ...attrs });
16
+ }
17
+ });
18
+ dispatch(tr);
19
+ }
20
+ return true;
21
+ };
22
+ }
23
+ export function makeToggleMark(markName) {
24
+ return (state, dispatch) => {
25
+ const mark = schema.marks[markName];
26
+ if (!mark)
27
+ return false;
28
+ if (state.selection.empty)
29
+ return false;
30
+ return toggleMark(mark)(state, dispatch);
31
+ };
32
+ }
33
+ // The "Note" toolbar button/shortcut does double duty: on an Action line it
34
+ // marks text as an inline [[ ]] note — the selection, or (with no selection)
35
+ // the whole line — leaving the line itself an Action. Inline notes aren't
36
+ // allowed on any other line type, so elsewhere it falls back to the original
37
+ // whole-block conversion to a standalone `note` block.
38
+ export function makeSetOrToggleNote() {
39
+ return (state, dispatch) => {
40
+ const { $from, $to, empty } = state.selection;
41
+ const inAction = $from.parent.type.name === 'action' && (empty || $from.sameParent($to));
42
+ if (!inAction)
43
+ return makeSetBlock('note')(state, dispatch);
44
+ const mark = schema.marks['note_mark'];
45
+ if (!mark)
46
+ return false;
47
+ let target = state;
48
+ if (empty) {
49
+ const lineStart = $from.start();
50
+ const lineEnd = $from.end();
51
+ if (lineEnd <= lineStart)
52
+ return false;
53
+ target = state.apply(state.tr.setSelection(TextSelection.create(state.doc, lineStart, lineEnd)));
54
+ }
55
+ return toggleMark(mark)(target, dispatch);
56
+ };
57
+ }
58
+ export { undo, redo };
@@ -0,0 +1 @@
1
+ export declare function SourceView(): import("react").JSX.Element;
@@ -0,0 +1,106 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useEffect, useRef } from 'react';
3
+ import { EditorState } from '@codemirror/state';
4
+ import { EditorView, keymap } from '@codemirror/view';
5
+ import { defaultKeymap, history, historyKeymap } from '@codemirror/commands';
6
+ import { HighlightStyle, syntaxHighlighting } from '@codemirror/language';
7
+ import { tags } from '@lezer/highlight';
8
+ import { sutraLanguage } from './sutra-lang';
9
+ import { useDocument } from '../context/DocumentContext';
10
+ import { setSourceView } from '../editor/editor-bus';
11
+ import { sourceFindHighlightExtension } from './find-highlight-source';
12
+ // Light theme matching the app's warm off-white palette.
13
+ // No internal scroll — the editor grows to content height and .cs-main scrolls.
14
+ const sutraTheme = EditorView.theme({
15
+ '&': {
16
+ width: '100%',
17
+ maxWidth: '960px',
18
+ fontSize: '12pt',
19
+ fontFamily: "'Courier New', Courier, monospace",
20
+ lineHeight: '1.5',
21
+ backgroundColor: 'transparent',
22
+ },
23
+ '.cm-scroller': { overflow: 'visible', lineHeight: '1.5' },
24
+ '.cm-content': { padding: '0', caretColor: '#1a1a18' },
25
+ '.cm-line': { padding: '0' },
26
+ '&.cm-focused': { outline: 'none' },
27
+ '.cm-cursor': { borderLeftColor: '#1a1a18' },
28
+ '.cm-selectionBackground, ::selection': { backgroundColor: '#b8d3f0' },
29
+ '&.cm-focused .cm-selectionBackground': { backgroundColor: '#b8d3f0' },
30
+ });
31
+ const sutraHighlight = HighlightStyle.define([
32
+ // ## Scene heading — dark teal, bold
33
+ { tag: tags.keyword, color: '#0a5c6a', fontWeight: 'bold' },
34
+ // # Section heading — medium slate
35
+ { tag: tags.heading, color: '#4a5568', fontWeight: 'bold' },
36
+ // @Character — warm brown/amber
37
+ { tag: tags.variableName, color: '#9c4221', fontWeight: 'bold' },
38
+ // Dialogue — dark ink, slightly indented feel via color
39
+ { tag: tags.labelName, color: '#2a3568' },
40
+ // Parenthetical — muted gray-green
41
+ { tag: tags.string, color: '#5a7a4a', fontStyle: 'italic' },
42
+ // >> Transition / centered — medium blue-gray
43
+ { tag: tags.operator, color: '#4a5a7a', fontWeight: 'bold' },
44
+ // ~ Lyrics — purple
45
+ { tag: tags.meta, color: '#6b46c1' },
46
+ // [[ Note ]] / <!-- comment --> — gray
47
+ { tag: tags.comment, color: '#9ca3af', fontStyle: 'italic' },
48
+ // & metadata key — teal
49
+ { tag: tags.attributeName, color: '#0694a2' },
50
+ // Frontmatter values — muted
51
+ { tag: tags.attributeValue, color: '#6b7280' },
52
+ // === page break, sigils — light gray
53
+ { tag: tags.punctuation, color: '#9ca3af' },
54
+ ]);
55
+ export function SourceView() {
56
+ const { text, setText } = useDocument();
57
+ const containerRef = useRef(null);
58
+ const viewRef = useRef(null);
59
+ // Track externally-driven text so we don't feed our own updates back
60
+ const lastTextRef = useRef(text);
61
+ useEffect(() => {
62
+ if (!containerRef.current)
63
+ return;
64
+ const view = new EditorView({
65
+ state: EditorState.create({
66
+ doc: text,
67
+ extensions: [
68
+ history(),
69
+ keymap.of([...defaultKeymap, ...historyKeymap]),
70
+ sutraLanguage,
71
+ sutraTheme,
72
+ syntaxHighlighting(sutraHighlight),
73
+ sourceFindHighlightExtension,
74
+ EditorView.lineWrapping,
75
+ EditorView.updateListener.of(update => {
76
+ if (update.docChanged) {
77
+ const newText = update.state.doc.toString();
78
+ lastTextRef.current = newText;
79
+ setText(newText);
80
+ }
81
+ }),
82
+ ],
83
+ }),
84
+ parent: containerRef.current,
85
+ });
86
+ viewRef.current = view;
87
+ setSourceView(view);
88
+ return () => {
89
+ setSourceView(null);
90
+ view.destroy();
91
+ viewRef.current = null;
92
+ };
93
+ // eslint-disable-next-line react-hooks/exhaustive-deps
94
+ }, []);
95
+ // Sync external text changes (e.g. switching back from formatted view)
96
+ useEffect(() => {
97
+ const view = viewRef.current;
98
+ if (!view || text === lastTextRef.current)
99
+ return;
100
+ lastTextRef.current = text;
101
+ view.dispatch({
102
+ changes: { from: 0, to: view.state.doc.length, insert: text },
103
+ });
104
+ }, [text]);
105
+ return _jsx("div", { ref: containerRef, className: "cs-source-view" });
106
+ }
@@ -0,0 +1,14 @@
1
+ import { StateField } from '@codemirror/state';
2
+ import type { DecorationSet } from '@codemirror/view';
3
+ export interface SourceMatch {
4
+ start: number;
5
+ end: number;
6
+ }
7
+ /** CodeMirror extension providing find-match highlighting in source view. */
8
+ export declare const sourceFindHighlightExtension: StateField<DecorationSet>;
9
+ /** Called by FindReplace whenever matches or active index change in source mode. */
10
+ export declare function setSourceFindHighlights(matches: SourceMatch[], activeIndex: number): void;
11
+ /** Called by FindReplace when the panel closes — clears all source-view highlights. */
12
+ export declare function clearSourceFindHighlights(): void;
13
+ /** Scroll the source view so the given match is visible. */
14
+ export declare function scrollToSourceMatch(match: SourceMatch): void;
@@ -0,0 +1,47 @@
1
+ import { StateEffect, StateField } from '@codemirror/state';
2
+ import { Decoration, EditorView } from '@codemirror/view';
3
+ import { getSourceView } from '../editor/editor-bus';
4
+ const setMatchesEffect = StateEffect.define();
5
+ function buildDecorations(matches, activeIndex, docLength) {
6
+ if (matches.length === 0)
7
+ return Decoration.none;
8
+ const decos = matches
9
+ .filter(m => m.start >= 0 && m.end <= docLength && m.start < m.end)
10
+ .map((m, i) => Decoration.mark({ class: i === activeIndex ? 'cs-find-active' : 'cs-find-match' }).range(m.start, m.end));
11
+ return Decoration.set(decos, true);
12
+ }
13
+ const findHighlightField = StateField.define({
14
+ create() {
15
+ return Decoration.none;
16
+ },
17
+ update(deco, tr) {
18
+ deco = deco.map(tr.changes);
19
+ for (const effect of tr.effects) {
20
+ if (effect.is(setMatchesEffect)) {
21
+ deco = buildDecorations(effect.value.matches, effect.value.activeIndex, tr.state.doc.length);
22
+ }
23
+ }
24
+ return deco;
25
+ },
26
+ provide: field => EditorView.decorations.from(field),
27
+ });
28
+ /** CodeMirror extension providing find-match highlighting in source view. */
29
+ export const sourceFindHighlightExtension = findHighlightField;
30
+ /** Called by FindReplace whenever matches or active index change in source mode. */
31
+ export function setSourceFindHighlights(matches, activeIndex) {
32
+ const view = getSourceView();
33
+ if (!view)
34
+ return;
35
+ view.dispatch({ effects: setMatchesEffect.of({ matches, activeIndex }) });
36
+ }
37
+ /** Called by FindReplace when the panel closes — clears all source-view highlights. */
38
+ export function clearSourceFindHighlights() {
39
+ setSourceFindHighlights([], 0);
40
+ }
41
+ /** Scroll the source view so the given match is visible. */
42
+ export function scrollToSourceMatch(match) {
43
+ const view = getSourceView();
44
+ if (!view)
45
+ return;
46
+ view.dispatch({ effects: EditorView.scrollIntoView(match.start, { y: 'center' }) });
47
+ }
@@ -0,0 +1,2 @@
1
+ import { LanguageSupport } from '@codemirror/language';
2
+ export declare const sutraLanguage: LanguageSupport;
@@ -0,0 +1,97 @@
1
+ import { StreamLanguage, LanguageSupport } from '@codemirror/language';
2
+ const sutra = StreamLanguage.define({
3
+ name: 'sutra',
4
+ startState: () => ({ inFrontmatter: false, lineNum: 0, afterCharacter: false }),
5
+ token(stream, state) {
6
+ state.lineNum++;
7
+ // Blank line — reset dialogue context, emit nothing
8
+ if (stream.match(/^\s*$/)) {
9
+ state.afterCharacter = false;
10
+ return null;
11
+ }
12
+ // Frontmatter delimiter ---
13
+ if (state.lineNum === 1 && stream.match(/^---\s*$/)) {
14
+ state.inFrontmatter = true;
15
+ return 'keyword';
16
+ }
17
+ if (state.inFrontmatter) {
18
+ if (stream.match(/^---\s*$/)) {
19
+ state.inFrontmatter = false;
20
+ return 'keyword';
21
+ }
22
+ // key: value lines inside frontmatter
23
+ if (stream.match(/^[A-Za-z][A-Za-z ]*:/))
24
+ return 'attributeName';
25
+ stream.skipToEnd();
26
+ return 'string';
27
+ }
28
+ // Page break ===
29
+ if (stream.match(/^===\s*$/)) {
30
+ state.afterCharacter = false;
31
+ return 'punctuation';
32
+ }
33
+ // Comment <!-- ... -->
34
+ if (stream.match(/^<!--[\s\S]*?-->\s*$/)) {
35
+ state.afterCharacter = false;
36
+ return 'comment';
37
+ }
38
+ // Note [[ ... ]]
39
+ if (stream.match(/^\[\[[\s\S]*?\]\]\s*$/)) {
40
+ state.afterCharacter = false;
41
+ return 'comment';
42
+ }
43
+ // Scene heading ## ...
44
+ if (stream.match(/^##/)) {
45
+ stream.skipToEnd();
46
+ state.afterCharacter = false;
47
+ return 'keyword';
48
+ }
49
+ // Section heading # ...
50
+ if (stream.match(/^#(?!#)/)) {
51
+ stream.skipToEnd();
52
+ state.afterCharacter = false;
53
+ return 'heading';
54
+ }
55
+ // Scene metadata & key: value
56
+ if (stream.match(/^&\s/)) {
57
+ stream.skipToEnd();
58
+ state.afterCharacter = false;
59
+ return 'attributeName';
60
+ }
61
+ // Character cue @name ...
62
+ if (stream.match(/^@/)) {
63
+ stream.skipToEnd();
64
+ state.afterCharacter = true;
65
+ return 'variableName';
66
+ }
67
+ // Centered or transition >> ...
68
+ if (stream.match(/^>>/)) {
69
+ stream.skipToEnd();
70
+ state.afterCharacter = false;
71
+ return 'operator';
72
+ }
73
+ // Lyrics ~ ...
74
+ if (stream.match(/^~\s/)) {
75
+ stream.skipToEnd();
76
+ state.afterCharacter = false;
77
+ return 'meta';
78
+ }
79
+ // Parenthetical (inside dialogue context)
80
+ if (state.afterCharacter && stream.match(/^\(/)) {
81
+ stream.skipToEnd();
82
+ return 'string';
83
+ }
84
+ // Dialogue (inside dialogue context) — styled differently from action
85
+ if (state.afterCharacter) {
86
+ stream.skipToEnd();
87
+ return 'labelName';
88
+ }
89
+ // Action — unstyled
90
+ stream.skipToEnd();
91
+ return null;
92
+ },
93
+ blankLine(state) {
94
+ state.afterCharacter = false;
95
+ },
96
+ });
97
+ export const sutraLanguage = new LanguageSupport(sutra);
@@ -0,0 +1,9 @@
1
+ export interface DictionaryManifest {
2
+ aff: string;
3
+ dic: string;
4
+ }
5
+ /**
6
+ * Dictionary manifest: maps BCP-47 language code → asset paths under public/dict/.
7
+ * The actual .dic/.aff files are not committed; see public/dict/README.md for acquisition.
8
+ */
9
+ export declare const DICTIONARIES: Record<string, DictionaryManifest>;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Dictionary manifest: maps BCP-47 language code → asset paths under public/dict/.
3
+ * The actual .dic/.aff files are not committed; see public/dict/README.md for acquisition.
4
+ */
5
+ export const DICTIONARIES = {
6
+ 'en': { aff: '/dict/en_US.aff', dic: '/dict/en_US.dic' },
7
+ 'hi': { aff: '/dict/hi_IN.aff', dic: '/dict/hi_IN.dic' },
8
+ 'ta': { aff: '/dict/ta_IN.aff', dic: '/dict/ta_IN.dic' },
9
+ 'te': { aff: '/dict/te_IN.aff', dic: '/dict/te_IN.dic' },
10
+ 'kn': { aff: '/dict/kn_IN.aff', dic: '/dict/kn_IN.dic' },
11
+ 'ml': { aff: '/dict/ml_IN.aff', dic: '/dict/ml_IN.dic' },
12
+ 'bn': { aff: '/dict/bn_IN.aff', dic: '/dict/bn_IN.dic' },
13
+ 'gu': { aff: '/dict/gu_IN.aff', dic: '/dict/gu_IN.dic' },
14
+ 'pa': { aff: '/dict/pa_IN.aff', dic: '/dict/pa_IN.dic' },
15
+ 'or': { aff: '/dict/or_IN.aff', dic: '/dict/or_IN.dic' },
16
+ };
@@ -0,0 +1,23 @@
1
+ export interface SpellChecker {
2
+ check(word: string): boolean;
3
+ suggest(word: string): string[];
4
+ }
5
+ /**
6
+ * Load a dictionary for the given language.
7
+ * In production: fetches .dic file, parses word list.
8
+ * In test/jsdom: fetch will fail gracefully, returning an empty checker.
9
+ */
10
+ export declare function loadDictionary(lang: string): Promise<SpellChecker>;
11
+ /**
12
+ * Add a word to the custom dictionary for a language.
13
+ * Persists in-memory; production would write to IndexedDB.
14
+ */
15
+ export declare function addToCustomDictionary(lang: string, word: string): void;
16
+ /**
17
+ * Create a spell checker from a word list (for testing).
18
+ */
19
+ export declare function createCheckerFromWords(words: string[]): SpellChecker;
20
+ /**
21
+ * Clear cached checkers (for testing).
22
+ */
23
+ export declare function clearCheckerCache(): void;
@@ -0,0 +1,94 @@
1
+ import { DICTIONARIES } from './dictionaries';
2
+ /**
3
+ * In-memory dictionary: Set-based word lookup.
4
+ * Production: load from .dic file; tests: use fixture words.
5
+ */
6
+ class SimpleSpellChecker {
7
+ words;
8
+ customWords;
9
+ constructor(words) {
10
+ this.words = new Set(words.map(w => w.toLowerCase().trim()).filter(Boolean));
11
+ this.customWords = new Set();
12
+ }
13
+ check(word) {
14
+ const lower = word.toLowerCase();
15
+ return this.words.has(lower) || this.customWords.has(lower);
16
+ }
17
+ suggest(_word) {
18
+ // Minimal: return empty (full Hunspell suggestions require .aff parsing)
19
+ return [];
20
+ }
21
+ addCustomWord(word) {
22
+ this.customWords.add(word.toLowerCase());
23
+ }
24
+ }
25
+ // Cache: lang → checker
26
+ const checkerCache = new Map();
27
+ // Custom words per-project (in-memory; production uses IndexedDB)
28
+ const customWords = new Map();
29
+ /**
30
+ * Load a dictionary for the given language.
31
+ * In production: fetches .dic file, parses word list.
32
+ * In test/jsdom: fetch will fail gracefully, returning an empty checker.
33
+ */
34
+ export async function loadDictionary(lang) {
35
+ if (checkerCache.has(lang)) {
36
+ return checkerCache.get(lang);
37
+ }
38
+ const manifest = DICTIONARIES[lang];
39
+ if (!manifest) {
40
+ // Fallback: empty checker for unknown language codes
41
+ const checker = new SimpleSpellChecker([]);
42
+ checkerCache.set(lang, checker);
43
+ return checker;
44
+ }
45
+ try {
46
+ // Fetch .dic file (word list, one per line)
47
+ const response = await fetch(manifest.dic);
48
+ if (!response.ok)
49
+ throw new Error(`Failed to load dictionary: ${manifest.dic}`);
50
+ const text = await response.text();
51
+ const words = text.split('\n').filter(Boolean);
52
+ const checker = new SimpleSpellChecker(words);
53
+ // Apply any cached custom words
54
+ const custom = customWords.get(lang);
55
+ if (custom) {
56
+ for (const w of custom)
57
+ checker.addCustomWord(w);
58
+ }
59
+ checkerCache.set(lang, checker);
60
+ return checker;
61
+ }
62
+ catch {
63
+ // Network unavailable (expected in dev/CI without dict files)
64
+ const checker = new SimpleSpellChecker([]);
65
+ checkerCache.set(lang, checker);
66
+ return checker;
67
+ }
68
+ }
69
+ /**
70
+ * Add a word to the custom dictionary for a language.
71
+ * Persists in-memory; production would write to IndexedDB.
72
+ */
73
+ export function addToCustomDictionary(lang, word) {
74
+ if (!customWords.has(lang))
75
+ customWords.set(lang, new Set());
76
+ customWords.get(lang).add(word.toLowerCase());
77
+ // Update cached checker if loaded
78
+ const checker = checkerCache.get(lang);
79
+ if (checker)
80
+ checker.addCustomWord(word);
81
+ }
82
+ /**
83
+ * Create a spell checker from a word list (for testing).
84
+ */
85
+ export function createCheckerFromWords(words) {
86
+ return new SimpleSpellChecker(words);
87
+ }
88
+ /**
89
+ * Clear cached checkers (for testing).
90
+ */
91
+ export function clearCheckerCache() {
92
+ checkerCache.clear();
93
+ customWords.clear();
94
+ }
@@ -0,0 +1,18 @@
1
+ import { Plugin } from 'prosemirror-state';
2
+ import { DecorationSet } from 'prosemirror-view';
3
+ export declare function setSpellcheckLanguage(lang: string): void;
4
+ /**
5
+ * Tokenize text into words (splitting on whitespace and punctuation).
6
+ * Returns array of {word, start, end} with character offsets.
7
+ * Uses Unicode letter/mark categories to support Indic scripts.
8
+ */
9
+ export declare function tokenizeWords(text: string): Array<{
10
+ word: string;
11
+ start: number;
12
+ end: number;
13
+ }>;
14
+ /**
15
+ * ProseMirror plugin that underlines misspelled words via Decoration API.
16
+ * Recomputes decorations on every doc change.
17
+ */
18
+ export declare function createSpellcheckPlugin(): Plugin<DecorationSet>;