@docmentis/udoc-editor 0.0.1 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (207) hide show
  1. package/LICENSE-APACHE +202 -0
  2. package/LICENSE-MIT +21 -0
  3. package/README.md +48 -0
  4. package/dist/arrange.d.ts +37 -0
  5. package/dist/arrange.d.ts.map +1 -0
  6. package/dist/arrange.js +431 -0
  7. package/dist/arrange.js.map +1 -0
  8. package/dist/clipboard.d.ts +12 -0
  9. package/dist/clipboard.d.ts.map +1 -0
  10. package/dist/clipboard.js +101 -0
  11. package/dist/clipboard.js.map +1 -0
  12. package/dist/commands.d.ts +12 -0
  13. package/dist/commands.d.ts.map +1 -0
  14. package/dist/commands.js +225 -0
  15. package/dist/commands.js.map +1 -0
  16. package/dist/components/ComboBox.d.ts +38 -0
  17. package/dist/components/ComboBox.d.ts.map +1 -0
  18. package/dist/components/ComboBox.js +57 -0
  19. package/dist/components/ComboBox.js.map +1 -0
  20. package/dist/components/ModeSwitch.d.ts +15 -0
  21. package/dist/components/ModeSwitch.d.ts.map +1 -0
  22. package/dist/components/ModeSwitch.js +94 -0
  23. package/dist/components/ModeSwitch.js.map +1 -0
  24. package/dist/components/NewSlideModal.d.ts +41 -0
  25. package/dist/components/NewSlideModal.d.ts.map +1 -0
  26. package/dist/components/NewSlideModal.js +136 -0
  27. package/dist/components/NewSlideModal.js.map +1 -0
  28. package/dist/components/PageControls.d.ts +78 -0
  29. package/dist/components/PageControls.d.ts.map +1 -0
  30. package/dist/components/PageControls.js +201 -0
  31. package/dist/components/PageControls.js.map +1 -0
  32. package/dist/components/PageSettingsModal.d.ts +27 -0
  33. package/dist/components/PageSettingsModal.d.ts.map +1 -0
  34. package/dist/components/PageSettingsModal.js +273 -0
  35. package/dist/components/PageSettingsModal.js.map +1 -0
  36. package/dist/components/PaintOptionsModal.d.ts +19 -0
  37. package/dist/components/PaintOptionsModal.d.ts.map +1 -0
  38. package/dist/components/PaintOptionsModal.js +103 -0
  39. package/dist/components/PaintOptionsModal.js.map +1 -0
  40. package/dist/components/TextControls.d.ts +49 -0
  41. package/dist/components/TextControls.d.ts.map +1 -0
  42. package/dist/components/TextControls.js +452 -0
  43. package/dist/components/TextControls.js.map +1 -0
  44. package/dist/context-menu.d.ts +46 -0
  45. package/dist/context-menu.d.ts.map +1 -0
  46. package/dist/context-menu.js +144 -0
  47. package/dist/context-menu.js.map +1 -0
  48. package/dist/edit-client.d.ts +121 -0
  49. package/dist/edit-client.d.ts.map +1 -0
  50. package/dist/edit-client.js +154 -0
  51. package/dist/edit-client.js.map +1 -0
  52. package/dist/edit-command.d.ts +7 -0
  53. package/dist/edit-command.d.ts.map +1 -0
  54. package/dist/edit-command.js +18 -0
  55. package/dist/edit-command.js.map +1 -0
  56. package/dist/edit-mode.d.ts +19 -0
  57. package/dist/edit-mode.d.ts.map +1 -0
  58. package/dist/edit-mode.js +214 -0
  59. package/dist/edit-mode.js.map +1 -0
  60. package/dist/editor.d.ts +101 -0
  61. package/dist/editor.d.ts.map +1 -0
  62. package/dist/editor.js +101 -0
  63. package/dist/editor.js.map +1 -0
  64. package/dist/fonts/faces.d.ts +28 -0
  65. package/dist/fonts/faces.d.ts.map +1 -0
  66. package/dist/fonts/faces.js +38 -0
  67. package/dist/fonts/faces.js.map +1 -0
  68. package/dist/fonts/preview.d.ts +98 -0
  69. package/dist/fonts/preview.d.ts.map +1 -0
  70. package/dist/fonts/preview.js +149 -0
  71. package/dist/fonts/preview.js.map +1 -0
  72. package/dist/formatting-marks.d.ts +23 -0
  73. package/dist/formatting-marks.d.ts.map +1 -0
  74. package/dist/formatting-marks.js +55 -0
  75. package/dist/formatting-marks.js.map +1 -0
  76. package/dist/grips.d.ts +14 -0
  77. package/dist/grips.d.ts.map +1 -0
  78. package/dist/grips.js +459 -0
  79. package/dist/grips.js.map +1 -0
  80. package/dist/i18n/ar.d.ts +4 -0
  81. package/dist/i18n/ar.d.ts.map +1 -0
  82. package/dist/i18n/ar.js +175 -0
  83. package/dist/i18n/ar.js.map +1 -0
  84. package/dist/i18n/de.d.ts +4 -0
  85. package/dist/i18n/de.d.ts.map +1 -0
  86. package/dist/i18n/de.js +175 -0
  87. package/dist/i18n/de.js.map +1 -0
  88. package/dist/i18n/en.d.ts +5 -0
  89. package/dist/i18n/en.d.ts.map +1 -0
  90. package/dist/i18n/en.js +176 -0
  91. package/dist/i18n/en.js.map +1 -0
  92. package/dist/i18n/es.d.ts +4 -0
  93. package/dist/i18n/es.d.ts.map +1 -0
  94. package/dist/i18n/es.js +175 -0
  95. package/dist/i18n/es.js.map +1 -0
  96. package/dist/i18n/fr.d.ts +4 -0
  97. package/dist/i18n/fr.d.ts.map +1 -0
  98. package/dist/i18n/fr.js +175 -0
  99. package/dist/i18n/fr.js.map +1 -0
  100. package/dist/i18n/index.d.ts +21 -0
  101. package/dist/i18n/index.d.ts.map +1 -0
  102. package/dist/i18n/index.js +42 -0
  103. package/dist/i18n/index.js.map +1 -0
  104. package/dist/i18n/ja.d.ts +4 -0
  105. package/dist/i18n/ja.d.ts.map +1 -0
  106. package/dist/i18n/ja.js +175 -0
  107. package/dist/i18n/ja.js.map +1 -0
  108. package/dist/i18n/ko.d.ts +4 -0
  109. package/dist/i18n/ko.d.ts.map +1 -0
  110. package/dist/i18n/ko.js +175 -0
  111. package/dist/i18n/ko.js.map +1 -0
  112. package/dist/i18n/messages.d.ts +316 -0
  113. package/dist/i18n/messages.d.ts.map +1 -0
  114. package/dist/i18n/messages.js +2 -0
  115. package/dist/i18n/messages.js.map +1 -0
  116. package/dist/i18n/pt-BR.d.ts +4 -0
  117. package/dist/i18n/pt-BR.d.ts.map +1 -0
  118. package/dist/i18n/pt-BR.js +175 -0
  119. package/dist/i18n/pt-BR.js.map +1 -0
  120. package/dist/i18n/ru.d.ts +4 -0
  121. package/dist/i18n/ru.d.ts.map +1 -0
  122. package/dist/i18n/ru.js +175 -0
  123. package/dist/i18n/ru.js.map +1 -0
  124. package/dist/i18n/zh-CN.d.ts +4 -0
  125. package/dist/i18n/zh-CN.d.ts.map +1 -0
  126. package/dist/i18n/zh-CN.js +175 -0
  127. package/dist/i18n/zh-CN.js.map +1 -0
  128. package/dist/i18n/zh-TW.d.ts +4 -0
  129. package/dist/i18n/zh-TW.d.ts.map +1 -0
  130. package/dist/i18n/zh-TW.js +175 -0
  131. package/dist/i18n/zh-TW.js.map +1 -0
  132. package/dist/icons.d.ts +97 -0
  133. package/dist/icons.d.ts.map +1 -0
  134. package/dist/icons.js +103 -0
  135. package/dist/icons.js.map +1 -0
  136. package/dist/index.d.ts +9 -0
  137. package/dist/index.d.ts.map +1 -0
  138. package/dist/index.js +14 -0
  139. package/dist/index.js.map +1 -0
  140. package/dist/insert.d.ts +21 -0
  141. package/dist/insert.d.ts.map +1 -0
  142. package/dist/insert.js +129 -0
  143. package/dist/insert.js.map +1 -0
  144. package/dist/menu-action.d.ts +73 -0
  145. package/dist/menu-action.d.ts.map +1 -0
  146. package/dist/menu-action.js +89 -0
  147. package/dist/menu-action.js.map +1 -0
  148. package/dist/mode.d.ts +21 -0
  149. package/dist/mode.d.ts.map +1 -0
  150. package/dist/mode.js +17 -0
  151. package/dist/mode.js.map +1 -0
  152. package/dist/new-slide.d.ts +21 -0
  153. package/dist/new-slide.d.ts.map +1 -0
  154. package/dist/new-slide.js +63 -0
  155. package/dist/new-slide.js.map +1 -0
  156. package/dist/page-controls.d.ts +20 -0
  157. package/dist/page-controls.d.ts.map +1 -0
  158. package/dist/page-controls.js +99 -0
  159. package/dist/page-controls.js.map +1 -0
  160. package/dist/paint.d.ts +52 -0
  161. package/dist/paint.d.ts.map +1 -0
  162. package/dist/paint.js +262 -0
  163. package/dist/paint.js.map +1 -0
  164. package/dist/ruler.d.ts +10 -0
  165. package/dist/ruler.d.ts.map +1 -0
  166. package/dist/ruler.js +97 -0
  167. package/dist/ruler.js.map +1 -0
  168. package/dist/state.d.ts +85 -0
  169. package/dist/state.d.ts.map +1 -0
  170. package/dist/state.js +28 -0
  171. package/dist/state.js.map +1 -0
  172. package/dist/styles.d.ts +2 -0
  173. package/dist/styles.d.ts.map +1 -0
  174. package/dist/styles.js +758 -0
  175. package/dist/styles.js.map +1 -0
  176. package/dist/tabs.d.ts +11 -0
  177. package/dist/tabs.d.ts.map +1 -0
  178. package/dist/tabs.js +153 -0
  179. package/dist/tabs.js.map +1 -0
  180. package/dist/text-format.d.ts +114 -0
  181. package/dist/text-format.d.ts.map +1 -0
  182. package/dist/text-format.js +315 -0
  183. package/dist/text-format.js.map +1 -0
  184. package/dist/tools.d.ts +35 -0
  185. package/dist/tools.d.ts.map +1 -0
  186. package/dist/tools.js +41 -0
  187. package/dist/tools.js.map +1 -0
  188. package/dist/version.d.ts +2 -0
  189. package/dist/version.d.ts.map +1 -0
  190. package/dist/version.js +7 -0
  191. package/dist/version.js.map +1 -0
  192. package/dist/worker/handlers.d.ts +11 -0
  193. package/dist/worker/handlers.d.ts.map +1 -0
  194. package/dist/worker/handlers.js +127 -0
  195. package/dist/worker/handlers.js.map +1 -0
  196. package/dist/worker/protocol.d.ts +190 -0
  197. package/dist/worker/protocol.d.ts.map +1 -0
  198. package/dist/worker/protocol.js +2 -0
  199. package/dist/worker/protocol.js.map +1 -0
  200. package/dist/worker/worker-source.d.ts +3 -0
  201. package/dist/worker/worker-source.d.ts.map +1 -0
  202. package/dist/worker/worker-source.js +11 -0
  203. package/dist/worker/worker.d.ts +2 -0
  204. package/dist/worker/worker.d.ts.map +1 -0
  205. package/dist/worker/worker.js +6 -0
  206. package/dist/worker/worker.js.map +1 -0
  207. package/package.json +68 -5
@@ -0,0 +1,214 @@
1
+ // Edit mode: the editor's extension of udoc-ui's shell.
2
+ import { selectionPaint, selectionTextFormat, subscribeSelector } from "@docmentis/udoc-ui/internal";
3
+ import { formatCommands } from "./commands.js";
4
+ import { CONTEXT_MENU, TABLE_CONTEXT_MENU } from "./context-menu.js";
5
+ import { createGrips } from "./grips.js";
6
+ import { createModeSwitch } from "./components/ModeSwitch.js";
7
+ import { createPaintOptionsModal } from "./components/PaintOptionsModal.js";
8
+ import { EditClient } from "./edit-client.js";
9
+ import { FORMATTING_MARKS_COMMAND, formattingMarksKey, mountFormattingMarks, setShowFormattingMarks, } from "./formatting-marks.js";
10
+ import { createI18n, MESSAGE_PACKS } from "./i18n/index.js";
11
+ import { insertCommands, insertImage, pickImage, place, placedShape } from "./insert.js";
12
+ import { runEditMenuAction } from "./menu-action.js";
13
+ import { mountNewSlide, newSlideCommand } from "./new-slide.js";
14
+ import { mountPageControls, PAGE_CONTROLS_SPACING, pageControlsShown } from "./page-controls.js";
15
+ import { ALL_MODES, EDIT_MODE } from "./mode.js";
16
+ import { editState, INITIAL_EDIT_STATE, updateEditState } from "./state.js";
17
+ import { RULER, rulerShown, setShowRuler } from "./ruler.js";
18
+ import { editorStyles } from "./styles.js";
19
+ import { editTabs } from "./tabs.js";
20
+ import { createEditTools } from "./tools.js";
21
+ /**
22
+ * Keep the document-derived parts of edit mode's state in step with the open
23
+ * document: the theme palette and font families pulled on open, the palette
24
+ * again per slide, both cleared while nothing is open, and the selection's
25
+ * resolved format mirrored from each selection report. Returns the teardown.
26
+ */
27
+ function mountDocumentState(host) {
28
+ const { store, client, edit } = host;
29
+ // Pull the current slide's resolved theme palette from the engine (the color
30
+ // picker's "Theme Colors"; the color dropdowns map it to swatches). Null for
31
+ // doc types without a theme, which keeps the picker's stand-in.
32
+ const refreshThemePalette = async () => {
33
+ updateEditState(store, { themePalette: await edit.themePalette() });
34
+ };
35
+ // Pull the open document's available font families (the engine's font
36
+ // registry) — the Text tab's font picker lists them. Empty for a doc type
37
+ // with no text font registry (PDF/image). Per-document, so pulled once on
38
+ // open (unlike the theme palette, which re-pulls per slide), and the whole
39
+ // list is stable across the session, so it's cached from there.
40
+ const refreshFontFamilies = async () => {
41
+ updateEditState(store, { fontFamilies: await edit.fontFamilySummaries() });
42
+ updateEditState(store, { loadedFontFamilyNames: await edit.loadedFontFamilyNames() });
43
+ };
44
+ const unsubs = [
45
+ // A document opening or closing drops the last one's palette and fonts.
46
+ subscribeSelector(store, (s) => s.status, (status) => {
47
+ if (status === "loading" || status === "empty") {
48
+ updateEditState(store, { themePalette: null, fontFamilies: [], loadedFontFamilyNames: [] });
49
+ }
50
+ }),
51
+ // Each opened document: its palette and its font list — async, off the
52
+ // open's critical path.
53
+ subscribeSelector(store, (s) => s.docGeneration, () => {
54
+ void refreshThemePalette();
55
+ void refreshFontFamilies();
56
+ }),
57
+ // Re-pull the theme palette when the viewed slide changes: a
58
+ // multi-master deck (or a slide with a `clrMapOvr`) re-themes per slide,
59
+ // so the picker's "Theme Colors" must track the current slide.
60
+ // Presentations only — a word document carries one theme, pulled once
61
+ // at open; it never re-themes per page.
62
+ subscribeSelector(store, (s) => s.pageIndex, () => {
63
+ if (store.getState().docType === "presentation")
64
+ void refreshThemePalette();
65
+ }),
66
+ // Mirror the selection's resolved character format onto the Text tab,
67
+ // and its color per channel onto the Fill / Line / Text Color dropdowns
68
+ // — projected from the engine's selection properties, every report.
69
+ client.onSelection((state) => updateEditState(store, {
70
+ selectionText: selectionTextFormat(state.properties),
71
+ selectionPaint: selectionPaint(state.properties),
72
+ })),
73
+ ];
74
+ return () => {
75
+ for (const unsub of unsubs)
76
+ unsub();
77
+ };
78
+ }
79
+ /** Whether the engine draws edit mode's authoring view in `s`. */
80
+ function editing(s) {
81
+ return s.mode === "edit";
82
+ }
83
+ /**
84
+ * Keep the engine drawing what only editing shows: objects that run off the
85
+ * page, and the prompts in empty placeholders. Both are sticky in the worker
86
+ * and start off, so pushed at once too. Returns the teardown.
87
+ */
88
+ function mountEditingView(host) {
89
+ const { store, edit } = host;
90
+ const show = (on) => {
91
+ // Objects that run off the page show only while editing; the engine
92
+ // applies it only in single-page view (where a stray object has no
93
+ // neighbours to spill over), so the other modes — and continuous —
94
+ // read as a clean page.
95
+ edit.setOverflowVisible(on);
96
+ // Empty-placeholder prompts (dashed frame + "Click to add …") are an
97
+ // editing affordance, so a document opened for reading shows none.
98
+ // Only presentations draw prompts, so this is a no-op for other doc
99
+ // types.
100
+ edit.setPlaceholderPrompts(on);
101
+ };
102
+ show(editing(store.getState()));
103
+ return subscribeSelector(store, editing, show);
104
+ }
105
+ /** Edit mode, as `options` configure it. */
106
+ export function editMode(options) {
107
+ const i18n = createI18n(options.locale, options.translations);
108
+ // The modes the host allows — every one unless it narrows them — and the
109
+ // one the editor opens in: the host's, if allowed, else the first allowed.
110
+ const allowedModes = options.allowedModes && options.allowedModes.length > 0 ? options.allowedModes : ALL_MODES;
111
+ const requestedMode = options.initialMode ?? "edit";
112
+ const initialMode = allowedModes.includes(requestedMode) ? requestedMode : allowedModes[0];
113
+ const showPageControls = options.showPageControls ?? true;
114
+ // What the shell lends, and what edit mode builds on it, from the mount on.
115
+ let host = null;
116
+ let tools = null;
117
+ let newSlide = null;
118
+ const grips = createGrips(() => tools);
119
+ const mountedTools = () => {
120
+ if (!tools)
121
+ throw new Error("udoc: edit mode is not mounted");
122
+ return tools;
123
+ };
124
+ return {
125
+ styles: editorStyles,
126
+ messages: MESSAGE_PACKS,
127
+ mode: EDIT_MODE,
128
+ initialMode,
129
+ initialState: {
130
+ ...INITIAL_EDIT_STATE,
131
+ showRuler: options.showRuler ?? INITIAL_EDIT_STATE.showRuler,
132
+ allowedModes,
133
+ showModeSwitch: options.showModeSwitch ?? allowedModes.length > 1,
134
+ },
135
+ tabs: editTabs,
136
+ commands: {
137
+ ...formatCommands(mountedTools),
138
+ formattingMarks: FORMATTING_MARKS_COMMAND,
139
+ createSlide: newSlideCommand(() => void newSlide?.open()),
140
+ ...insertCommands(() => {
141
+ if (host)
142
+ pickImage(host);
143
+ }),
144
+ },
145
+ spacing: (state) => (showPageControls && pageControlsShown(state) ? PAGE_CONTROLS_SPACING : null),
146
+ keydown(e) {
147
+ if (host)
148
+ formattingMarksKey(e, host.store);
149
+ },
150
+ menuAction(action) {
151
+ if (tools)
152
+ runEditMenuAction(tools, action);
153
+ },
154
+ // Edit mode's acts on the selection, a table's rows added over one; view
155
+ // mode keeps the shell's.
156
+ contextMenuItems: (state, inTable) => (editing(state) ? (inTable ? TABLE_CONTEXT_MENU : CONTEXT_MENU) : null),
157
+ guideBand: (state) => (rulerShown(state) ? RULER : null),
158
+ placedShape,
159
+ selectionChrome: grips.chrome,
160
+ pressCanvas: (x, y, _ev, canvas) => grips.press(x, y, canvas),
161
+ canvasCursor: (x, y) => grips.cursor(x, y),
162
+ place: (tool, page, p0, p1) => (host ? place(host, tool, page, p0, p1) : Promise.resolve()),
163
+ mount(lent) {
164
+ // What the shell lends, with edit mode's own client over the worker.
165
+ const mounted = { ...lent, edit: new EditClient(lent.client) };
166
+ host = mounted;
167
+ tools = createEditTools(mounted, i18n);
168
+ const modeSwitch = createModeSwitch(i18n);
169
+ modeSwitch.mount(mounted.modeSlot, mounted.store);
170
+ const paintOptionsModal = createPaintOptionsModal(i18n);
171
+ paintOptionsModal.mount(mounted.root);
172
+ const unmountDocumentState = mountDocumentState(mounted);
173
+ const unmountEditingView = mountEditingView(mounted);
174
+ const unmountPageControls = showPageControls ? mountPageControls(mounted, i18n) : null;
175
+ const unmountFormattingMarks = mountFormattingMarks(mounted);
176
+ newSlide = mountNewSlide(mounted, i18n);
177
+ return () => {
178
+ newSlide?.destroy();
179
+ newSlide = null;
180
+ unmountFormattingMarks();
181
+ unmountPageControls?.();
182
+ unmountEditingView();
183
+ unmountDocumentState();
184
+ tools?.clipboard.destroy();
185
+ paintOptionsModal.destroy();
186
+ modeSwitch.destroy();
187
+ tools = null;
188
+ host = null;
189
+ };
190
+ },
191
+ setShowFormattingMarks(visible) {
192
+ if (host)
193
+ setShowFormattingMarks(host.store, visible);
194
+ },
195
+ setShowRuler(visible) {
196
+ if (host)
197
+ setShowRuler(host.store, visible);
198
+ },
199
+ currentMode() {
200
+ return (host?.store.getState().mode ?? initialMode);
201
+ },
202
+ setMode(mode) {
203
+ // Ignored outside the host's modes; the shell ignores one the
204
+ // session isn't entitled to.
205
+ if (host && editState(host.store.getState()).allowedModes.includes(mode)) {
206
+ host.store.dispatch({ type: "SET_MODE", mode });
207
+ }
208
+ },
209
+ insertImage(bytes, contentType) {
210
+ return host ? insertImage(host, bytes, contentType) : Promise.resolve();
211
+ },
212
+ };
213
+ }
214
+ //# sourceMappingURL=edit-mode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edit-mode.js","sourceRoot":"","sources":["../src/edit-mode.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,101 @@
1
+ import { UDocBase } from "@docmentis/udoc-ui";
2
+ import type { LocalCollaborationServiceOptions, UDocEvents, UDocOptions } from "@docmentis/udoc-ui";
3
+ import type { Messages } from "./i18n/index.js";
4
+ import type { EditorMode } from "./mode.js";
5
+ /** Options for {@link UDocEditor.create}: the common ones, and edit mode's. Every field is optional; each says its default. */
6
+ export interface UDocEditorOptions extends UDocOptions {
7
+ /** Strings that replace the built-in ones, by key — the host's own wording,
8
+ * or a language the editor doesn't ship. Default none. */
9
+ translations?: Partial<Messages>;
10
+ /** The mode the editor opens in. Default `"edit"`. */
11
+ initialMode?: EditorMode;
12
+ /** The modes the user may switch between. Default every mode. */
13
+ allowedModes?: readonly EditorMode[];
14
+ /** Show the mode switcher. Default `true` when more than one mode is allowed. */
15
+ showModeSwitch?: boolean;
16
+ /** Show edit mode's per-page controls — the page-control rail
17
+ * (`udoc:page-actions`) and the insert-between-pages affordance
18
+ * (`udoc:page-insert`) — with the wider page spacing they sit in. Default
19
+ * `true`; a host shipping its own page organizer sets `false`. */
20
+ showPageControls?: boolean;
21
+ /** Show the page ruler on paged documents. Default `true`;
22
+ * {@link UDocEditor.setShowRuler} changes it. */
23
+ showRuler?: boolean;
24
+ }
25
+ /** The editor's event map: the common events, and edit mode's. Subscribe with {@link UDocEditor.on}. */
26
+ export interface UDocEditorEvents extends UDocEvents {
27
+ /** Fires when the editor mode changes (via {@link UDocEditor.setMode} or the mode switcher). */
28
+ "mode:changed": {
29
+ mode: EditorMode;
30
+ previousMode: EditorMode;
31
+ };
32
+ }
33
+ /**
34
+ * The document editor — construct it with {@link UDocEditor.create} and drive
35
+ * it with `open` / `close` / `destroy`.
36
+ */
37
+ export declare class UDocEditor extends UDocBase<UDocEditorEvents> {
38
+ #private;
39
+ /** This package's version, from its `package.json`. */
40
+ static readonly version: string;
41
+ private constructor();
42
+ /**
43
+ * Create an editor mounted into `container`. Spawns the render worker and loads
44
+ * the WASM (async), then mounts the UI. Rejects with an `unsupported`
45
+ * `UDocError` on runtimes without OffscreenCanvas-in-worker support.
46
+ */
47
+ static create(container: HTMLElement, options?: UDocEditorOptions): Promise<UDocEditor>;
48
+ /**
49
+ * Start a local collaboration service on the document in `bytes`, and
50
+ * resolve with its id — the page's own udoc server for one document, for
51
+ * editors in this page to {@link openLocal} and
52
+ * {@link joinLocalCollaboration}.
53
+ *
54
+ * Editors that each {@link open} the same bytes can't collaborate: a
55
+ * document's ids are minted as its parts load, so two editors that load
56
+ * them in a different order hold different ids for the same content. The
57
+ * service imports the document once, in a worker of its own, and keeps its
58
+ * udoc package, which every editor opening it shares; then it serves their
59
+ * collaboration, as udoc-server serves one for a document it keeps. It ends
60
+ * when the last editor joined to it leaves.
61
+ *
62
+ * Its session is started as an editor's is, under `options`: it rejects
63
+ * when the license refuses it.
64
+ */
65
+ static startLocalCollaborationService(bytes: Uint8Array, options?: LocalCollaborationServiceOptions): Promise<string>;
66
+ /**
67
+ * Insert the image file `bytes` as a picture on the current slide, centred
68
+ * and scaled down to fit, then selected — what the Insert tab's Image does
69
+ * with the file it asks for. `contentType` is the file's MIME type
70
+ * (`image/png`, …); an empty one is read from the bytes' own signature. One
71
+ * committing edit (one undo step). The image never enters the CRDT: it
72
+ * reaches a peer through {@link opaquePartsSince}. Rejects for a document
73
+ * that isn't a presentation, or bytes no codec reads.
74
+ */
75
+ insertImage(bytes: Uint8Array, contentType: string): Promise<void>;
76
+ /**
77
+ * Show or hide the page ruler on paged documents (PDF / DOCX / PPTX). A
78
+ * user preference; the ruler is additionally hidden automatically in
79
+ * `"view"` mode (a reading pose needs no measurement chrome). A spreadsheet's
80
+ * row/column headers are essential and never affected.
81
+ */
82
+ setShowRuler(visible: boolean): void;
83
+ /**
84
+ * Show or hide formatting marks — `¶` at each paragraph end, a dot in each
85
+ * space, an arrow in each tab, `↵` at each line break — on wordprocessing
86
+ * documents; the same toggle as the ribbon's button. A
87
+ * user preference, off by default; the marks are editing chrome, so they're
88
+ * additionally hidden outside `"edit"` mode.
89
+ */
90
+ setShowFormattingMarks(visible: boolean): void;
91
+ /** The current editor mode; `"mode:changed"` fires when it changes. */
92
+ get mode(): EditorMode;
93
+ /**
94
+ * Switch the editor mode. Ignored if `mode` isn't in the configured
95
+ * `allowedModes`. Drives the toolbar's command set and pointer behavior.
96
+ */
97
+ setMode(mode: EditorMode): void;
98
+ /** Tear down components, listeners, and the render worker. */
99
+ destroy(): void;
100
+ }
101
+ //# sourceMappingURL=editor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../src/editor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,KAAK,EAAE,gCAAgC,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAKpG,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAO5C,+HAA+H;AAC/H,MAAM,WAAW,iBAAkB,SAAQ,WAAW;IAClD;+DAC2D;IAC3D,YAAY,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IACjC,sDAAsD;IACtD,WAAW,CAAC,EAAE,UAAU,CAAC;IACzB,iEAAiE;IACjE,YAAY,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IACrC,iFAAiF;IACjF,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;uEAGmE;IACnE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;sDACkD;IAClD,SAAS,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,wGAAwG;AACxG,MAAM,WAAW,gBAAiB,SAAQ,UAAU;IAChD,gGAAgG;IAChG,cAAc,EAAE;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,YAAY,EAAE,UAAU,CAAA;KAAE,CAAC;CAClE;AAED;;;GAGG;AACH,qBAAa,UAAW,SAAQ,QAAQ,CAAC,gBAAgB,CAAC;;IACtD,uDAAuD;IACvD,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAmB;IAKlD,OAAO;IAWP;;;;OAIG;IACH,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,WAAW,EAAE,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,UAAU,CAAC;IAY3F;;;;;;;;;;;;;;;;OAgBG;IACH,MAAM,CAAC,8BAA8B,CACjC,KAAK,EAAE,UAAU,EACjB,OAAO,GAAE,gCAAqC,GAC/C,OAAO,CAAC,MAAM,CAAC;IAIlB;;;;;;;;OAQG;IACH,WAAW,CAAC,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlE;;;;;OAKG;IACH,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAIpC;;;;;;OAMG;IACH,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAI9C,uEAAuE;IACvE,IAAI,IAAI,IAAI,UAAU,CAErB;IAED;;;OAGG;IACH,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI;IAI/B,8DAA8D;IACrD,OAAO,IAAI,IAAI;CAI3B"}
package/dist/editor.js ADDED
@@ -0,0 +1,101 @@
1
+ import { UDocBase } from "@docmentis/udoc-ui";
2
+ import { createAs, startLocalCollaborationService, subscribeSelector } from "@docmentis/udoc-ui/internal";
3
+ import { editMode } from "./edit-mode.js";
4
+ import { WRAPPER_VERSION } from "./version.js";
5
+ import { startRenderWorker } from "./worker/worker-source.js";
6
+ /** This package, as the wrapper it reports to the engine. */
7
+ const EDITOR_WRAPPER = { name: "udoc-editor", version: WRAPPER_VERSION };
8
+ /**
9
+ * The document editor — construct it with {@link UDocEditor.create} and drive
10
+ * it with `open` / `close` / `destroy`.
11
+ */
12
+ export class UDocEditor extends UDocBase {
13
+ /** This package's version, from its `package.json`. */
14
+ static version = WRAPPER_VERSION;
15
+ #unsubscribeMode;
16
+ #editMode;
17
+ constructor(shell, editMode) {
18
+ super(shell);
19
+ this.#editMode = editMode;
20
+ this.#unsubscribeMode = subscribeSelector(shell.store,
21
+ // The shell's mode is view or edit mode's own.
22
+ (s) => s.mode, (mode, previousMode) => this.emit("mode:changed", { mode, previousMode }));
23
+ }
24
+ /**
25
+ * Create an editor mounted into `container`. Spawns the render worker and loads
26
+ * the WASM (async), then mounts the UI. Rejects with an `unsupported`
27
+ * `UDocError` on runtimes without OffscreenCanvas-in-worker support.
28
+ */
29
+ static create(container, options = {}) {
30
+ const mode = editMode(options);
31
+ return createAs(container, options, EDITOR_WRAPPER, startRenderWorker, mode, (shell) => new UDocEditor(shell, mode));
32
+ }
33
+ /**
34
+ * Start a local collaboration service on the document in `bytes`, and
35
+ * resolve with its id — the page's own udoc server for one document, for
36
+ * editors in this page to {@link openLocal} and
37
+ * {@link joinLocalCollaboration}.
38
+ *
39
+ * Editors that each {@link open} the same bytes can't collaborate: a
40
+ * document's ids are minted as its parts load, so two editors that load
41
+ * them in a different order hold different ids for the same content. The
42
+ * service imports the document once, in a worker of its own, and keeps its
43
+ * udoc package, which every editor opening it shares; then it serves their
44
+ * collaboration, as udoc-server serves one for a document it keeps. It ends
45
+ * when the last editor joined to it leaves.
46
+ *
47
+ * Its session is started as an editor's is, under `options`: it rejects
48
+ * when the license refuses it.
49
+ */
50
+ static startLocalCollaborationService(bytes, options = {}) {
51
+ return startLocalCollaborationService(bytes, options, EDITOR_WRAPPER);
52
+ }
53
+ /**
54
+ * Insert the image file `bytes` as a picture on the current slide, centred
55
+ * and scaled down to fit, then selected — what the Insert tab's Image does
56
+ * with the file it asks for. `contentType` is the file's MIME type
57
+ * (`image/png`, …); an empty one is read from the bytes' own signature. One
58
+ * committing edit (one undo step). The image never enters the CRDT: it
59
+ * reaches a peer through {@link opaquePartsSince}. Rejects for a document
60
+ * that isn't a presentation, or bytes no codec reads.
61
+ */
62
+ insertImage(bytes, contentType) {
63
+ return this.#editMode.insertImage(bytes, contentType);
64
+ }
65
+ /**
66
+ * Show or hide the page ruler on paged documents (PDF / DOCX / PPTX). A
67
+ * user preference; the ruler is additionally hidden automatically in
68
+ * `"view"` mode (a reading pose needs no measurement chrome). A spreadsheet's
69
+ * row/column headers are essential and never affected.
70
+ */
71
+ setShowRuler(visible) {
72
+ this.#editMode.setShowRuler(visible);
73
+ }
74
+ /**
75
+ * Show or hide formatting marks — `¶` at each paragraph end, a dot in each
76
+ * space, an arrow in each tab, `↵` at each line break — on wordprocessing
77
+ * documents; the same toggle as the ribbon's button. A
78
+ * user preference, off by default; the marks are editing chrome, so they're
79
+ * additionally hidden outside `"edit"` mode.
80
+ */
81
+ setShowFormattingMarks(visible) {
82
+ this.#editMode.setShowFormattingMarks(visible);
83
+ }
84
+ /** The current editor mode; `"mode:changed"` fires when it changes. */
85
+ get mode() {
86
+ return this.#editMode.currentMode();
87
+ }
88
+ /**
89
+ * Switch the editor mode. Ignored if `mode` isn't in the configured
90
+ * `allowedModes`. Drives the toolbar's command set and pointer behavior.
91
+ */
92
+ setMode(mode) {
93
+ this.#editMode.setMode(mode);
94
+ }
95
+ /** Tear down components, listeners, and the render worker. */
96
+ destroy() {
97
+ this.#unsubscribeMode();
98
+ super.destroy();
99
+ }
100
+ }
101
+ //# sourceMappingURL=editor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editor.js","sourceRoot":"","sources":["../src/editor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,OAAO,EAAE,QAAQ,EAAE,8BAA8B,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAE1G,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAI1C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAE9D,6DAA6D;AAC7D,MAAM,cAAc,GAAY,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,eAAe,EAAE,CAAC;AA6BlF;;;GAGG;AACH,MAAM,OAAO,UAAW,SAAQ,QAA0B;IACtD,uDAAuD;IACvD,MAAM,CAAU,OAAO,GAAW,eAAe,CAAC;IAEzC,gBAAgB,CAAa;IAC7B,SAAS,CAAW;IAE7B,YAAoB,KAAc,EAAE,QAAkB;QAClD,KAAK,CAAC,KAAK,CAAC,CAAC;QACb,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;QAC1B,IAAI,CAAC,gBAAgB,GAAG,iBAAiB,CACrC,KAAK,CAAC,KAAK;QACX,+CAA+C;QAC/C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAkB,EAC3B,CAAC,IAAI,EAAE,YAAY,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAC5E,CAAC;IACN,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,MAAM,CAAC,SAAsB,EAAE,UAA6B,EAAE;QACjE,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC/B,OAAO,QAAQ,CACX,SAAS,EACT,OAAO,EACP,cAAc,EACd,iBAAiB,EACjB,IAAI,EACJ,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,CACzC,CAAC;IACN,CAAC;IAED;;;;;;;;;;;;;;;;OAgBG;IACH,MAAM,CAAC,8BAA8B,CACjC,KAAiB,EACjB,UAA4C,EAAE;QAE9C,OAAO,8BAA8B,CAAC,KAAK,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC;IAC1E,CAAC;IAED;;;;;;;;OAQG;IACH,WAAW,CAAC,KAAiB,EAAE,WAAmB;QAC9C,OAAO,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;IAC1D,CAAC;IAED;;;;;OAKG;IACH,YAAY,CAAC,OAAgB;QACzB,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;IACzC,CAAC;IAED;;;;;;OAMG;IACH,sBAAsB,CAAC,OAAgB;QACnC,IAAI,CAAC,SAAS,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC;IACnD,CAAC;IAED,uEAAuE;IACvE,IAAI,IAAI;QACJ,OAAO,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC;IACxC,CAAC;IAED;;;OAGG;IACH,OAAO,CAAC,IAAgB;QACpB,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC;IAED,8DAA8D;IACrD,OAAO;QACZ,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACxB,KAAK,CAAC,OAAO,EAAE,CAAC;IACpB,CAAC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Which faces a font change will actually have to render in.
3
+ *
4
+ * A selection is rarely one face. Applying a family to a paragraph with a bold
5
+ * word in it produces text in *two* faces, and each is a separate binary — get
6
+ * only the regular one and the bold word still lays out in a stand-in and
7
+ * reflows when its own download lands, which is the whole thing the preload
8
+ * exists to avoid.
9
+ *
10
+ * The engine already answers this, in the form the ribbon's B / I buttons show:
11
+ * it folds the selection's resolved runs into a consensus per axis, and
12
+ * `"mixed"` means both values are present. That fold is a real walk over the
13
+ * composed runs, so `"mixed"` is a fact about the text, not a guess.
14
+ */
15
+ import type { TextFormatState } from "@docmentis/udoc-ui/internal";
16
+ /**
17
+ * The `(bold, italic)` faces to get here before applying a family.
18
+ *
19
+ * One face for a uniform selection, two when one axis is mixed, four when both
20
+ * are. Four is an **over-approximation**: a selection that is mixed on both axes
21
+ * need not contain all four combinations (bold text and italic text, but nothing
22
+ * bold-italic). Narrowing it would mean a new engine read of the distinct faces
23
+ * rather than the per-axis fold, and the cost of being wrong is one extra font
24
+ * fetched — the same fetch that would have happened anyway if the selection did
25
+ * span it.
26
+ */
27
+ export declare function facesToLoad(bold: TextFormatState, italic: TextFormatState): Array<[boolean, boolean]>;
28
+ //# sourceMappingURL=faces.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"faces.d.ts","sourceRoot":"","sources":["../../src/fonts/faces.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAEnE;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,eAAe,EAAE,MAAM,EAAE,eAAe,GAAG,KAAK,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAMrG"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Which faces a font change will actually have to render in.
3
+ *
4
+ * A selection is rarely one face. Applying a family to a paragraph with a bold
5
+ * word in it produces text in *two* faces, and each is a separate binary — get
6
+ * only the regular one and the bold word still lays out in a stand-in and
7
+ * reflows when its own download lands, which is the whole thing the preload
8
+ * exists to avoid.
9
+ *
10
+ * The engine already answers this, in the form the ribbon's B / I buttons show:
11
+ * it folds the selection's resolved runs into a consensus per axis, and
12
+ * `"mixed"` means both values are present. That fold is a real walk over the
13
+ * composed runs, so `"mixed"` is a fact about the text, not a guess.
14
+ */
15
+ /**
16
+ * The `(bold, italic)` faces to get here before applying a family.
17
+ *
18
+ * One face for a uniform selection, two when one axis is mixed, four when both
19
+ * are. Four is an **over-approximation**: a selection that is mixed on both axes
20
+ * need not contain all four combinations (bold text and italic text, but nothing
21
+ * bold-italic). Narrowing it would mean a new engine read of the distinct faces
22
+ * rather than the per-axis fold, and the cost of being wrong is one extra font
23
+ * fetched — the same fetch that would have happened anyway if the selection did
24
+ * span it.
25
+ */
26
+ export function facesToLoad(bold, italic) {
27
+ const faces = [];
28
+ for (const isBold of values(bold)) {
29
+ for (const isItalic of values(italic))
30
+ faces.push([isBold, isItalic]);
31
+ }
32
+ return faces;
33
+ }
34
+ /** The values one axis takes across the selection. */
35
+ function values(state) {
36
+ return state === "mixed" ? [false, true] : [state === "on"];
37
+ }
38
+ //# sourceMappingURL=faces.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"faces.js","sourceRoot":"","sources":["../../src/fonts/faces.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH;;;;;;;;;;GAUG;AACH,MAAM,UAAU,WAAW,CAAC,IAAqB,EAAE,MAAuB;IACtE,MAAM,KAAK,GAA8B,EAAE,CAAC;IAC5C,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;QAChC,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,MAAM,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC1E,CAAC;IACD,OAAO,KAAK,CAAC;AACjB,CAAC;AAED,sDAAsD;AACtD,SAAS,MAAM,CAAC,KAAsB;IAClC,OAAO,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC;AAChE,CAAC"}
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Font **specimens** — a family's name drawn in its own typeface, so the picker
3
+ * shows the face instead of naming it.
4
+ *
5
+ * Two paths, and a family's `sourceType` picks which. Most families the browser
6
+ * can draw itself: a `Local` one it already answers to by name, a `Url` one it
7
+ * loads as a `FontFace`, a `Google` one it pulls from the css2 API. Those rows
8
+ * stay live text — they restyle with the theme, ellipse when the panel is
9
+ * narrow, and read out to a screen reader — and this module's whole job for them
10
+ * is to get the face into `document.fonts` and let the browser repaint on its
11
+ * own.
12
+ *
13
+ * The rest — `Embedded`, `OfficeCompatible`, `AdobeStandard` — have no bytes
14
+ * outside wasm, so nothing here can name them. Those come back from the engine
15
+ * as a PNG **alpha mask** and are held as object URLs for a CSS `mask-image`
16
+ * over `currentColor`: the specimen then takes the theme's text color, and a
17
+ * light/dark switch needs no redraw.
18
+ *
19
+ * A `Url` family's address is **not** in its source type — the tag carries no
20
+ * data at all — so the host supplies it from the same list it registered with
21
+ * `registerUrlFonts`. It is the only side that ever had it.
22
+ *
23
+ * Every family is worked on **once**. The picker asks for its visible window on
24
+ * every scroll step, so `request` has to be cheap to re-call — it is the only
25
+ * thing standing between a flick through ~2000 families and a request storm.
26
+ */
27
+ import type { FontSourceType } from "@docmentis/udoc-wasm";
28
+ import type { FontPreviewImage } from "../worker/protocol.js";
29
+ /** An engine-drawn specimen: a mask to point CSS at, and the box to draw it in. */
30
+ export interface FontSpecimen {
31
+ /** Object URL of a PNG whose alpha is the glyph coverage. */
32
+ url: string;
33
+ /** CSS px. */
34
+ width: number;
35
+ /** CSS px. */
36
+ height: number;
37
+ /**
38
+ * The transparent bleed on every side, CSS px. Offset the element by
39
+ * `-bleed` to put the specimen's pen origin where a text row's is — the
40
+ * raster is grown all round to hold overhanging ink.
41
+ */
42
+ bleed: number;
43
+ }
44
+ export interface FontPreviewLoaderOptions {
45
+ /**
46
+ * Draw a specimen the browser can't — the worker's `renderFontPreview`.
47
+ * Resolving `null` means the engine had nothing to draw; the row keeps the
48
+ * plain name.
49
+ */
50
+ render: (family: string, size: number) => Promise<FontPreviewImage | null>;
51
+ /** The em to draw engine specimens at, in CSS px. */
52
+ size: number;
53
+ /**
54
+ * Where a `Url` family's font actually is, keyed by family — the same
55
+ * addresses the host handed to `registerUrlFonts`. Omit it when the host
56
+ * registered none, which leaves `Url` families showing their plain name.
57
+ */
58
+ urls?: ReadonlyMap<string, string>;
59
+ /** Where css2 is asked for a `Google` family's face — the worker's own. */
60
+ googleFontEndpoint: string;
61
+ /**
62
+ * Called once per batch of arrivals (coalesced to a microtask), so a caller
63
+ * re-renders the rows it has mounted rather than being patched per row.
64
+ * Never called for browser-loaded faces — the browser repaints those itself.
65
+ */
66
+ onSpecimens: () => void;
67
+ }
68
+ export interface FontPreviewLoader {
69
+ /**
70
+ * Make sure these families can be shown in their own face. Families already
71
+ * worked on are skipped, so calling this on every scroll step is fine.
72
+ */
73
+ request: (families: readonly FontSpecimenRequest[]) => void;
74
+ /**
75
+ * The engine-drawn specimen for `family`, once it has landed.
76
+ *
77
+ * The object URLs behind these are held for the loader's life, which is the
78
+ * page's: a face is drawn once and the picker reopens against the same
79
+ * masks, so there is no point at which revoking one would be right.
80
+ */
81
+ specimen: (family: string) => FontSpecimen | undefined;
82
+ }
83
+ /** One row's worth of what the loader needs: which family, and whose face it is. */
84
+ export interface FontSpecimenRequest {
85
+ family: string;
86
+ sourceType: FontSourceType;
87
+ }
88
+ /** Whether the engine has to draw this family — nothing outside wasm holds its
89
+ * bytes. The complement of the three the browser can load itself. */
90
+ export declare function isEngineDrawn(sourceType: FontSourceType): boolean;
91
+ export declare function createFontPreviewLoader(options: FontPreviewLoaderOptions): FontPreviewLoader;
92
+ /**
93
+ * `family` as a CSS `font-family` value, quoted and escaped — the form to drop
94
+ * into a style attribute. A family name is arbitrary text (it comes out of a
95
+ * document's font table), so it can't be interpolated raw.
96
+ */
97
+ export declare function cssFontFamily(family: string): string;
98
+ //# sourceMappingURL=preview.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview.d.ts","sourceRoot":"","sources":["../../src/fonts/preview.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAU9D,mFAAmF;AACnF,MAAM,WAAW,YAAY;IACzB,6DAA6D;IAC7D,GAAG,EAAE,MAAM,CAAC;IACZ,cAAc;IACd,KAAK,EAAE,MAAM,CAAC;IACd,cAAc;IACd,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,wBAAwB;IACrC;;;;OAIG;IACH,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IAC3E,qDAAqD;IACrD,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,IAAI,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,2EAA2E;IAC3E,kBAAkB,EAAE,MAAM,CAAC;IAC3B;;;;OAIG;IACH,WAAW,EAAE,MAAM,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB;IAC9B;;;OAGG;IACH,OAAO,EAAE,CAAC,QAAQ,EAAE,SAAS,mBAAmB,EAAE,KAAK,IAAI,CAAC;IAC5D;;;;;;OAMG;IACH,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,YAAY,GAAG,SAAS,CAAC;CAC1D;AAED,oFAAoF;AACpF,MAAM,WAAW,mBAAmB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,cAAc,CAAC;CAC9B;AAED;sEACsE;AACtE,wBAAgB,aAAa,CAAC,UAAU,EAAE,cAAc,GAAG,OAAO,CAEjE;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,wBAAwB,GAAG,iBAAiB,CAsG5F;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEpD"}