@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,22 @@
1
+ /** Screenplay pagination rules — format conventions, not per-style visual choices, so
2
+ * they live here rather than in ScreenplayStyleDefinition: no style (built-in or
3
+ * user-imported) gets to end a page on a character cue. Consumed by both export
4
+ * paths, which express the same rule differently: DOCX via `keepNext`/`keepLines`
5
+ * paragraph properties (docx-adapter.ts), PDF/print via `break-after`/`break-inside`
6
+ * (print-adapter.ts). The live editor has no pagination, so it ignores these. */
7
+ /** Elements that must not be the last thing on a page — a scene heading or character
8
+ * cue stranded at the bottom with its action/dialogue overleaf is the classic
9
+ * screenplay pagination error. A parenthetical is included for the same reason: it
10
+ * belongs to the dialogue line that follows it. */
11
+ export const KEEP_WITH_NEXT_ELEMENTS = [
12
+ 'sceneHeading', 'character', 'parenthetical', 'section',
13
+ ];
14
+ /** Elements short enough that splitting them across a page boundary is always wrong.
15
+ * Deliberately excludes action/dialogue/lyrics/note — those can legitimately run
16
+ * longer than a page, so they get orphan/widow control instead of an unbreakable box. */
17
+ export const KEEP_TOGETHER_ELEMENTS = [
18
+ 'sceneHeading', 'character', 'parenthetical', 'transition', 'section',
19
+ ];
20
+ /** Minimum lines of a breakable element left on either side of a page boundary. Two is
21
+ * the standard screenplay/typography minimum (a single stranded line reads as an error). */
22
+ export const MIN_ORPHAN_WIDOW_LINES = 2;
@@ -0,0 +1,6 @@
1
+ import type { ScreenplayStyleDefinition } from './types.js';
2
+ /** Builds the screenplay-specific portion of the PDF/print-preview `<style>` block
3
+ * (packages/app/src/file/workflow-reports.ts's buildScreenplayPrintHtml) from a style
4
+ * definition. UI chrome (print button, page-break rule, dual-dialogue column layout)
5
+ * stays hardcoded in workflow-reports.ts — only the parametrized visual properties live here. */
6
+ export declare function styleToPrintCss(style: ScreenplayStyleDefinition, pageFormat?: 'letter' | 'a4'): string;
@@ -0,0 +1,288 @@
1
+ import { MIN_ORPHAN_WIDOW_LINES } from './pagination.js';
2
+ function color(el) {
3
+ return el.color ? `#${el.color}` : 'black';
4
+ }
5
+ function fontProps(el) {
6
+ const lines = [`font-size: ${el.fontSizePt}pt;`, `color: ${color(el)};`];
7
+ if (el.bold)
8
+ lines.push('font-weight: bold;');
9
+ if (el.italic)
10
+ lines.push('font-style: italic;');
11
+ if (el.underline)
12
+ lines.push('text-decoration: underline;');
13
+ if (el.align)
14
+ lines.push(`text-align: ${el.align};`);
15
+ return lines.join('\n ');
16
+ }
17
+ /** Screenplay page-break rules for PDF/print — the CSS half of pagination.ts (DOCX gets
18
+ * the same rules as keepNext/keepLines). `page-break-*` is emitted alongside the modern
19
+ * `break-*` because print engines are uneven about which spelling they honor. */
20
+ const KEEP_WITH_NEXT = `
21
+ break-after: avoid;
22
+ page-break-after: avoid;
23
+ break-inside: avoid;
24
+ page-break-inside: avoid;`;
25
+ const KEEP_TOGETHER = `
26
+ break-inside: avoid;
27
+ page-break-inside: avoid;`;
28
+ /** For elements that may legitimately run longer than a page: don't forbid the break,
29
+ * just refuse to strand one line on either side of it. */
30
+ const ORPHAN_WIDOW = `
31
+ orphans: ${MIN_ORPHAN_WIDOW_LINES};
32
+ widows: ${MIN_ORPHAN_WIDOW_LINES};`;
33
+ function marginProps(el) {
34
+ const lines = [];
35
+ if (el.marginLeftPct !== undefined)
36
+ lines.push(`margin-left: ${el.marginLeftPct}%;`);
37
+ if (el.marginRightPct !== undefined)
38
+ lines.push(`margin-right: ${el.marginRightPct}%;`);
39
+ lines.push(`margin-top: ${el.spaceBeforePt ?? 0}pt;`);
40
+ lines.push(`margin-bottom: ${el.spaceAfterPt ?? 0}pt;`);
41
+ return lines.join('\n ');
42
+ }
43
+ /** Builds the screenplay-specific portion of the PDF/print-preview `<style>` block
44
+ * (packages/app/src/file/workflow-reports.ts's buildScreenplayPrintHtml) from a style
45
+ * definition. UI chrome (print button, page-break rule, dual-dialogue column layout)
46
+ * stays hardcoded in workflow-reports.ts — only the parametrized visual properties live here. */
47
+ export function styleToPrintCss(style, pageFormat = 'letter') {
48
+ const e = style.elements;
49
+ const contentWidthIn = (pageFormat === 'a4' ? 8.27 : 8.5) - style.page.marginLeftIn - style.page.marginRightIn;
50
+ // The style's own font first, then its explicit per-script overrides (e.g. Traditional's
51
+ // Noto Serif Tamil) so they win over the generic Indic fallback that always follows — this
52
+ // HTML has no per-span language tagging, so one comprehensive stack has to do the work the
53
+ // editor's .cs-lang-* rules split across classes. Overrides are style-specific, so unlike
54
+ // the fixed Noto Sans fallback list they must come from the style itself, not be hardcoded —
55
+ // otherwise every style would render Indic scripts in whatever the *last*-defined style's
56
+ // overrides asked for.
57
+ const overrideFonts = Object.values(style.complexScriptFontOverrides ?? {});
58
+ // Noto Sans comes right after the style's own fonts: it is the Latin fallback (app spec
59
+ // §4.4) and its bundled file carries every ISO 15919 letter and combining mark, which the
60
+ // Indic families' Latin subsets do not. Its unicode-range stops at Latin, so Indic text
61
+ // still falls through to the script-specific faces below.
62
+ const fontStack = [...new Set([
63
+ `'${style.fontFamily}'`,
64
+ ...overrideFonts.map(f => `'${f}'`),
65
+ "'Noto Sans'",
66
+ "'Noto Sans Tamil'", "'Noto Sans Devanagari'", "'Noto Sans Telugu'", "'Noto Sans Kannada'",
67
+ "'Noto Sans Malayalam'", "'Noto Sans Bengali'", "'Noto Sans Gujarati'", "'Noto Sans Gurmukhi'",
68
+ "'Noto Sans Oriya'", 'sans-serif',
69
+ ])].join(', ');
70
+ return `
71
+ @page {
72
+ /* Stated, not left to the print dialog's default: print-paginator.ts fills
73
+ fixed-height page boxes, so the paper it fills them for has to be the paper
74
+ the browser actually prints on (and it's the same page: field the DOCX
75
+ export already honors). */
76
+ size: ${pageFormat === 'a4' ? 'A4' : 'letter'};
77
+ margin: ${style.page.marginTopIn}in ${style.page.marginRightIn}in ${style.page.marginBottomIn}in ${style.page.marginLeftIn}in;
78
+ }
79
+ body {
80
+ font-family: ${fontStack};
81
+ margin: 0;
82
+ padding: 0;
83
+ background: white;
84
+ color: black;
85
+ font-size: 11pt;
86
+ }
87
+ /* Cover layouts — one of these two classes is on .print-cover-page, picked by
88
+ the style's coverLayout (see types.ts). Both wrap the same markup: a
89
+ .print-cover-top block (title / by-line / logline) and a .print-cover-bottom
90
+ block (date / contact). */
91
+ .print-cover-centered {
92
+ height: 80vh;
93
+ display: flex;
94
+ flex-direction: column;
95
+ align-items: center;
96
+ justify-content: center;
97
+ text-align: center;
98
+ }
99
+ .print-cover-corners {
100
+ height: 88vh;
101
+ display: flex;
102
+ flex-direction: column;
103
+ justify-content: space-between;
104
+ text-align: left;
105
+ }
106
+ /* Down from the top edge, not glued to it — the reference script starts its
107
+ title roughly a quarter of the way down the page. */
108
+ .print-cover-corners .print-cover-top {
109
+ padding-top: 20%;
110
+ }
111
+ .print-cover-corners .print-cover-bottom {
112
+ align-self: flex-end;
113
+ padding-bottom: 6%;
114
+ max-width: 45%;
115
+ }
116
+ .print-cover-corners .print-cover-logline {
117
+ margin-top: 12pt;
118
+ max-width: 75%;
119
+ }
120
+ /* The corner block is its own visual group: the centered layout's big
121
+ separating margins would push it off the page bottom. */
122
+ .print-cover-corners .print-cover-date,
123
+ .print-cover-corners .print-cover-contact {
124
+ margin-top: 0;
125
+ }
126
+ .print-cover-title {
127
+ ${fontProps(e.title)}
128
+ text-transform: uppercase;
129
+ margin-bottom: 20px;
130
+ }
131
+ .print-cover-by {
132
+ font-size: 12pt;
133
+ margin: 10px 0;
134
+ }
135
+ .print-cover-author {
136
+ ${fontProps(e.author)}
137
+ }
138
+ .print-cover-logline {
139
+ ${fontProps(e.logline)}
140
+ margin-top: 40px;
141
+ max-width: 600px;
142
+ white-space: pre-line;
143
+ }
144
+ .print-cover-date {
145
+ font-size: 10pt;
146
+ margin-top: 50px;
147
+ color: #777;
148
+ }
149
+ .print-cover-contact {
150
+ font-size: 11pt;
151
+ margin-top: 24px;
152
+ color: #888;
153
+ white-space: pre-line;
154
+ }
155
+
156
+ /* The preview lays out at exactly the printable width, on screen as well as on
157
+ paper. print-paginator.ts measures where the page breaks fall in the live
158
+ window, so if the on-screen line breaks differed from the printed ones (a
159
+ 1280px-wide window wraps far later than a 6in column) every page it filled
160
+ would overflow its sheet when printed. */
161
+ #print-flow, #print-pages, .print-cover-page {
162
+ width: ${contentWidthIn}in;
163
+ margin-left: auto;
164
+ margin-right: auto;
165
+ }
166
+
167
+ /* One printed sheet of body content, built by print-paginator.ts: an exact
168
+ page-height box (set inline, from the paper size) so the browser puts exactly
169
+ one on each sheet, with the running header at its top. */
170
+ .print-page {
171
+ break-after: page;
172
+ page-break-after: always;
173
+ box-sizing: border-box;
174
+ overflow: visible;
175
+ }
176
+ .print-page:last-child {
177
+ break-after: auto;
178
+ page-break-after: auto;
179
+ }
180
+ .print-page-body {
181
+ position: relative;
182
+ display: flow-root; /* so a first child's margin-top counts inside the page */
183
+ }
184
+ .print-page-header {
185
+ display: flex;
186
+ justify-content: space-between;
187
+ align-items: baseline;
188
+ font-size: ${e.action.fontSizePt}pt;
189
+ font-style: italic;
190
+ margin-bottom: 24pt;
191
+ }
192
+ @media screen {
193
+ .print-page {
194
+ border-bottom: 1px dashed #ccc;
195
+ margin-bottom: 24px;
196
+ }
197
+ }
198
+
199
+ /* Screenplay items */
200
+ .print-scene-heading {
201
+ ${fontProps(e.sceneHeading)}
202
+ text-transform: uppercase;
203
+ ${marginProps(e.sceneHeading)}
204
+ display: flex;
205
+ justify-content: space-between;${KEEP_WITH_NEXT}
206
+ }
207
+ .print-action {
208
+ ${fontProps(e.action)}
209
+ ${marginProps(e.action)}
210
+ line-height: 1.4;${ORPHAN_WIDOW}
211
+ }
212
+ .print-character-block {
213
+ margin-top: ${e.character.spaceBeforePt ?? 0}pt;
214
+ margin-bottom: ${e.character.spaceAfterPt ?? 0}pt;
215
+ }
216
+ .print-character {
217
+ ${fontProps(e.character)}
218
+ margin-left: ${e.character.marginLeftPct ?? 0}%;
219
+ margin-bottom: 2pt;${KEEP_WITH_NEXT}
220
+ }
221
+ .print-parenthetical {
222
+ ${fontProps(e.parenthetical)}
223
+ margin-left: ${e.parenthetical.marginLeftPct ?? 0}%;
224
+ margin-right: ${e.parenthetical.marginRightPct ?? 0}%;
225
+ margin-bottom: 2pt;${KEEP_WITH_NEXT}
226
+ }
227
+ .print-dialogue {
228
+ ${fontProps(e.dialogue)}
229
+ ${marginProps(e.dialogue)}
230
+ line-height: 1.3;${ORPHAN_WIDOW}
231
+ }
232
+ .print-transition {
233
+ ${fontProps(e.transition)}
234
+ ${marginProps(e.transition)}
235
+ text-transform: uppercase;${KEEP_TOGETHER}
236
+ }
237
+ .print-centered {
238
+ ${fontProps(e.centered)}
239
+ ${marginProps(e.centered)}
240
+ }
241
+ .print-lyrics {
242
+ ${fontProps(e.lyrics)}
243
+ ${marginProps(e.lyrics)}${ORPHAN_WIDOW}
244
+ }
245
+ .print-note {
246
+ background: #fffbeb;
247
+ border-left: 2px solid #d97706;
248
+ padding: 4px 8px;
249
+ ${fontProps(e.note)}
250
+ ${marginProps(e.note)}
251
+ }
252
+ .print-comment {
253
+ ${fontProps(e.comment)}
254
+ ${marginProps(e.comment)}
255
+ }
256
+ .print-section {
257
+ ${fontProps(e.section)}
258
+ ${marginProps(e.section)}${KEEP_WITH_NEXT}
259
+ }
260
+ .print-page-break {
261
+ page-break-after: always;
262
+ }
263
+
264
+ /* Dual dialogue */
265
+ .print-dual-dialogue {
266
+ display: flex;
267
+ margin-top: 6pt;
268
+ margin-bottom: 6pt;
269
+ }
270
+ .print-dual-column {
271
+ flex: 1;
272
+ min-width: 0;
273
+ }
274
+ .print-left-column {
275
+ margin-right: 20px;
276
+ }
277
+ .print-right-column {
278
+ margin-left: 20px;
279
+ }
280
+ .print-dual-column .print-character {
281
+ margin-left: 10%;
282
+ }
283
+ .print-dual-column .print-parenthetical,
284
+ .print-dual-column .print-dialogue {
285
+ margin-left: 10%;
286
+ margin-right: 5%;
287
+ }`;
288
+ }
@@ -0,0 +1,6 @@
1
+ import type { ScreenplayStyleDefinition } from './types.js';
2
+ /** Resolves a style id (usually from frontmatter's `style:` field) to a definition.
3
+ * Falls back to the default style when the id is missing or unrecognized — e.g. a
4
+ * document referencing a custom style the current machine/browser hasn't imported. */
5
+ export declare function resolveStyle(id: string | undefined, customStyles: ScreenplayStyleDefinition[]): ScreenplayStyleDefinition;
6
+ export declare function allStyles(customStyles: ScreenplayStyleDefinition[]): ScreenplayStyleDefinition[];
@@ -0,0 +1,14 @@
1
+ import { DEFAULT_STYLE_ID } from './types.js';
2
+ import { BUILTIN_STYLES, getBuiltinStyle } from './builtin-styles.js';
3
+ /** Resolves a style id (usually from frontmatter's `style:` field) to a definition.
4
+ * Falls back to the default style when the id is missing or unrecognized — e.g. a
5
+ * document referencing a custom style the current machine/browser hasn't imported. */
6
+ export function resolveStyle(id, customStyles) {
7
+ const wanted = id ?? DEFAULT_STYLE_ID;
8
+ return getBuiltinStyle(wanted)
9
+ ?? customStyles.find(s => s.id === wanted)
10
+ ?? getBuiltinStyle(DEFAULT_STYLE_ID);
11
+ }
12
+ export function allStyles(customStyles) {
13
+ return [...BUILTIN_STYLES, ...customStyles];
14
+ }