@rtif-sdk/web 1.0.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 (215) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +67 -0
  3. package/dist/block-drag-handler.d.ts +189 -0
  4. package/dist/block-drag-handler.d.ts.map +1 -0
  5. package/dist/block-drag-handler.js +745 -0
  6. package/dist/block-drag-handler.js.map +1 -0
  7. package/dist/block-renderer.d.ts +402 -0
  8. package/dist/block-renderer.d.ts.map +1 -0
  9. package/dist/block-renderer.js +424 -0
  10. package/dist/block-renderer.js.map +1 -0
  11. package/dist/clipboard.d.ts +178 -0
  12. package/dist/clipboard.d.ts.map +1 -0
  13. package/dist/clipboard.js +432 -0
  14. package/dist/clipboard.js.map +1 -0
  15. package/dist/command-bus.d.ts +113 -0
  16. package/dist/command-bus.d.ts.map +1 -0
  17. package/dist/command-bus.js +70 -0
  18. package/dist/command-bus.js.map +1 -0
  19. package/dist/composition.d.ts +220 -0
  20. package/dist/composition.d.ts.map +1 -0
  21. package/dist/composition.js +271 -0
  22. package/dist/composition.js.map +1 -0
  23. package/dist/content-extraction.d.ts +69 -0
  24. package/dist/content-extraction.d.ts.map +1 -0
  25. package/dist/content-extraction.js +228 -0
  26. package/dist/content-extraction.js.map +1 -0
  27. package/dist/content-handler-file.d.ts +40 -0
  28. package/dist/content-handler-file.d.ts.map +1 -0
  29. package/dist/content-handler-file.js +91 -0
  30. package/dist/content-handler-file.js.map +1 -0
  31. package/dist/content-handler-image.d.ts +82 -0
  32. package/dist/content-handler-image.d.ts.map +1 -0
  33. package/dist/content-handler-image.js +120 -0
  34. package/dist/content-handler-image.js.map +1 -0
  35. package/dist/content-handler-url.d.ts +129 -0
  36. package/dist/content-handler-url.d.ts.map +1 -0
  37. package/dist/content-handler-url.js +244 -0
  38. package/dist/content-handler-url.js.map +1 -0
  39. package/dist/content-handlers.d.ts +67 -0
  40. package/dist/content-handlers.d.ts.map +1 -0
  41. package/dist/content-handlers.js +263 -0
  42. package/dist/content-handlers.js.map +1 -0
  43. package/dist/content-pipeline.d.ts +383 -0
  44. package/dist/content-pipeline.d.ts.map +1 -0
  45. package/dist/content-pipeline.js +232 -0
  46. package/dist/content-pipeline.js.map +1 -0
  47. package/dist/cursor-nav.d.ts +149 -0
  48. package/dist/cursor-nav.d.ts.map +1 -0
  49. package/dist/cursor-nav.js +230 -0
  50. package/dist/cursor-nav.js.map +1 -0
  51. package/dist/cursor-rect.d.ts +65 -0
  52. package/dist/cursor-rect.d.ts.map +1 -0
  53. package/dist/cursor-rect.js +98 -0
  54. package/dist/cursor-rect.js.map +1 -0
  55. package/dist/drop-indicator.d.ts +108 -0
  56. package/dist/drop-indicator.d.ts.map +1 -0
  57. package/dist/drop-indicator.js +236 -0
  58. package/dist/drop-indicator.js.map +1 -0
  59. package/dist/editor.d.ts +41 -0
  60. package/dist/editor.d.ts.map +1 -0
  61. package/dist/editor.js +710 -0
  62. package/dist/editor.js.map +1 -0
  63. package/dist/floating-toolbar.d.ts +93 -0
  64. package/dist/floating-toolbar.d.ts.map +1 -0
  65. package/dist/floating-toolbar.js +159 -0
  66. package/dist/floating-toolbar.js.map +1 -0
  67. package/dist/index.d.ts +62 -0
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +119 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/input-bridge.d.ts +273 -0
  72. package/dist/input-bridge.d.ts.map +1 -0
  73. package/dist/input-bridge.js +884 -0
  74. package/dist/input-bridge.js.map +1 -0
  75. package/dist/link-popover.d.ts +38 -0
  76. package/dist/link-popover.d.ts.map +1 -0
  77. package/dist/link-popover.js +278 -0
  78. package/dist/link-popover.js.map +1 -0
  79. package/dist/mark-renderer.d.ts +275 -0
  80. package/dist/mark-renderer.d.ts.map +1 -0
  81. package/dist/mark-renderer.js +210 -0
  82. package/dist/mark-renderer.js.map +1 -0
  83. package/dist/perf.d.ts +145 -0
  84. package/dist/perf.d.ts.map +1 -0
  85. package/dist/perf.js +260 -0
  86. package/dist/perf.js.map +1 -0
  87. package/dist/plugin-kit.d.ts +265 -0
  88. package/dist/plugin-kit.d.ts.map +1 -0
  89. package/dist/plugin-kit.js +234 -0
  90. package/dist/plugin-kit.js.map +1 -0
  91. package/dist/plugins/alignment-plugin.d.ts +68 -0
  92. package/dist/plugins/alignment-plugin.d.ts.map +1 -0
  93. package/dist/plugins/alignment-plugin.js +98 -0
  94. package/dist/plugins/alignment-plugin.js.map +1 -0
  95. package/dist/plugins/block-utils.d.ts +113 -0
  96. package/dist/plugins/block-utils.d.ts.map +1 -0
  97. package/dist/plugins/block-utils.js +191 -0
  98. package/dist/plugins/block-utils.js.map +1 -0
  99. package/dist/plugins/blockquote-plugin.d.ts +39 -0
  100. package/dist/plugins/blockquote-plugin.d.ts.map +1 -0
  101. package/dist/plugins/blockquote-plugin.js +88 -0
  102. package/dist/plugins/blockquote-plugin.js.map +1 -0
  103. package/dist/plugins/bold-plugin.d.ts +37 -0
  104. package/dist/plugins/bold-plugin.d.ts.map +1 -0
  105. package/dist/plugins/bold-plugin.js +48 -0
  106. package/dist/plugins/bold-plugin.js.map +1 -0
  107. package/dist/plugins/callout-plugin.d.ts +100 -0
  108. package/dist/plugins/callout-plugin.d.ts.map +1 -0
  109. package/dist/plugins/callout-plugin.js +200 -0
  110. package/dist/plugins/callout-plugin.js.map +1 -0
  111. package/dist/plugins/code-block-plugin.d.ts +62 -0
  112. package/dist/plugins/code-block-plugin.d.ts.map +1 -0
  113. package/dist/plugins/code-block-plugin.js +176 -0
  114. package/dist/plugins/code-block-plugin.js.map +1 -0
  115. package/dist/plugins/code-plugin.d.ts +37 -0
  116. package/dist/plugins/code-plugin.d.ts.map +1 -0
  117. package/dist/plugins/code-plugin.js +48 -0
  118. package/dist/plugins/code-plugin.js.map +1 -0
  119. package/dist/plugins/embed-plugin.d.ts +90 -0
  120. package/dist/plugins/embed-plugin.d.ts.map +1 -0
  121. package/dist/plugins/embed-plugin.js +147 -0
  122. package/dist/plugins/embed-plugin.js.map +1 -0
  123. package/dist/plugins/font-family-plugin.d.ts +58 -0
  124. package/dist/plugins/font-family-plugin.d.ts.map +1 -0
  125. package/dist/plugins/font-family-plugin.js +57 -0
  126. package/dist/plugins/font-family-plugin.js.map +1 -0
  127. package/dist/plugins/font-size-plugin.d.ts +57 -0
  128. package/dist/plugins/font-size-plugin.d.ts.map +1 -0
  129. package/dist/plugins/font-size-plugin.js +56 -0
  130. package/dist/plugins/font-size-plugin.js.map +1 -0
  131. package/dist/plugins/heading-plugin.d.ts +52 -0
  132. package/dist/plugins/heading-plugin.d.ts.map +1 -0
  133. package/dist/plugins/heading-plugin.js +114 -0
  134. package/dist/plugins/heading-plugin.js.map +1 -0
  135. package/dist/plugins/hr-plugin.d.ts +33 -0
  136. package/dist/plugins/hr-plugin.d.ts.map +1 -0
  137. package/dist/plugins/hr-plugin.js +75 -0
  138. package/dist/plugins/hr-plugin.js.map +1 -0
  139. package/dist/plugins/image-plugin.d.ts +115 -0
  140. package/dist/plugins/image-plugin.d.ts.map +1 -0
  141. package/dist/plugins/image-plugin.js +199 -0
  142. package/dist/plugins/image-plugin.js.map +1 -0
  143. package/dist/plugins/indent-plugin.d.ts +62 -0
  144. package/dist/plugins/indent-plugin.d.ts.map +1 -0
  145. package/dist/plugins/indent-plugin.js +128 -0
  146. package/dist/plugins/indent-plugin.js.map +1 -0
  147. package/dist/plugins/index.d.ts +45 -0
  148. package/dist/plugins/index.d.ts.map +1 -0
  149. package/dist/plugins/index.js +42 -0
  150. package/dist/plugins/index.js.map +1 -0
  151. package/dist/plugins/italic-plugin.d.ts +37 -0
  152. package/dist/plugins/italic-plugin.d.ts.map +1 -0
  153. package/dist/plugins/italic-plugin.js +48 -0
  154. package/dist/plugins/italic-plugin.js.map +1 -0
  155. package/dist/plugins/link-plugin.d.ts +129 -0
  156. package/dist/plugins/link-plugin.d.ts.map +1 -0
  157. package/dist/plugins/link-plugin.js +212 -0
  158. package/dist/plugins/link-plugin.js.map +1 -0
  159. package/dist/plugins/list-plugin.d.ts +53 -0
  160. package/dist/plugins/list-plugin.d.ts.map +1 -0
  161. package/dist/plugins/list-plugin.js +309 -0
  162. package/dist/plugins/list-plugin.js.map +1 -0
  163. package/dist/plugins/mark-utils.d.ts +173 -0
  164. package/dist/plugins/mark-utils.d.ts.map +1 -0
  165. package/dist/plugins/mark-utils.js +425 -0
  166. package/dist/plugins/mark-utils.js.map +1 -0
  167. package/dist/plugins/mention-plugin.d.ts +191 -0
  168. package/dist/plugins/mention-plugin.d.ts.map +1 -0
  169. package/dist/plugins/mention-plugin.js +295 -0
  170. package/dist/plugins/mention-plugin.js.map +1 -0
  171. package/dist/plugins/strikethrough-plugin.d.ts +37 -0
  172. package/dist/plugins/strikethrough-plugin.d.ts.map +1 -0
  173. package/dist/plugins/strikethrough-plugin.js +48 -0
  174. package/dist/plugins/strikethrough-plugin.js.map +1 -0
  175. package/dist/plugins/text-color-plugin.d.ts +57 -0
  176. package/dist/plugins/text-color-plugin.d.ts.map +1 -0
  177. package/dist/plugins/text-color-plugin.js +56 -0
  178. package/dist/plugins/text-color-plugin.js.map +1 -0
  179. package/dist/plugins/underline-plugin.d.ts +37 -0
  180. package/dist/plugins/underline-plugin.d.ts.map +1 -0
  181. package/dist/plugins/underline-plugin.js +48 -0
  182. package/dist/plugins/underline-plugin.js.map +1 -0
  183. package/dist/presets.d.ts +95 -0
  184. package/dist/presets.d.ts.map +1 -0
  185. package/dist/presets.js +159 -0
  186. package/dist/presets.js.map +1 -0
  187. package/dist/renderer.d.ts +125 -0
  188. package/dist/renderer.d.ts.map +1 -0
  189. package/dist/renderer.js +415 -0
  190. package/dist/renderer.js.map +1 -0
  191. package/dist/scroll-to-cursor.d.ts +25 -0
  192. package/dist/scroll-to-cursor.d.ts.map +1 -0
  193. package/dist/scroll-to-cursor.js +59 -0
  194. package/dist/scroll-to-cursor.js.map +1 -0
  195. package/dist/selection-sync.d.ts +159 -0
  196. package/dist/selection-sync.d.ts.map +1 -0
  197. package/dist/selection-sync.js +527 -0
  198. package/dist/selection-sync.js.map +1 -0
  199. package/dist/shortcut-handler.d.ts +98 -0
  200. package/dist/shortcut-handler.d.ts.map +1 -0
  201. package/dist/shortcut-handler.js +155 -0
  202. package/dist/shortcut-handler.js.map +1 -0
  203. package/dist/toolbar.d.ts +103 -0
  204. package/dist/toolbar.d.ts.map +1 -0
  205. package/dist/toolbar.js +134 -0
  206. package/dist/toolbar.js.map +1 -0
  207. package/dist/trigger-manager.d.ts +205 -0
  208. package/dist/trigger-manager.d.ts.map +1 -0
  209. package/dist/trigger-manager.js +466 -0
  210. package/dist/trigger-manager.js.map +1 -0
  211. package/dist/types.d.ts +216 -0
  212. package/dist/types.d.ts.map +1 -0
  213. package/dist/types.js +2 -0
  214. package/dist/types.js.map +1 -0
  215. package/package.json +30 -0
@@ -0,0 +1,232 @@
1
+ /**
2
+ * Content pipeline — unified ingestion for paste, drop, and programmatic input.
3
+ *
4
+ * The content pipeline routes incoming content items through a priority-ordered
5
+ * chain of handlers. Each handler declares which MIME types it accepts and
6
+ * processes matching items into RTIF operations. All operations from a single
7
+ * process() call are batched into one engine.dispatch() for a single undo group.
8
+ *
9
+ * @module
10
+ * @see docs/plans/web/03-content-pipeline.md
11
+ */
12
+ import { deleteSelectionOps } from './clipboard.js';
13
+ // ---------------------------------------------------------------------------
14
+ // matchesMime helper
15
+ // ---------------------------------------------------------------------------
16
+ /**
17
+ * Check whether a MIME type matches any of the given patterns.
18
+ *
19
+ * Supports exact match, wildcard subtypes (e.g., `image/*`), and
20
+ * catch-all (`*\/*`).
21
+ *
22
+ * @param contentType - The MIME type to test (e.g., 'text/plain')
23
+ * @param patterns - Array of MIME patterns to match against
24
+ * @returns true if the content type matches any pattern
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * matchesMime('image/png', ['image/*']); // true
29
+ * matchesMime('text/plain', ['text/html']); // false
30
+ * matchesMime('text/plain', ['*\/*']); // true (catch-all)
31
+ * ```
32
+ */
33
+ export function matchesMime(contentType, patterns) {
34
+ for (const pattern of patterns) {
35
+ // Catch-all
36
+ if (pattern === '*/*')
37
+ return true;
38
+ // Wildcard subtype: 'image/*' matches 'image/png'
39
+ if (pattern.endsWith('/*')) {
40
+ const prefix = pattern.slice(0, -1); // 'image/'
41
+ if (contentType.startsWith(prefix))
42
+ return true;
43
+ continue;
44
+ }
45
+ // Exact match
46
+ if (contentType === pattern)
47
+ return true;
48
+ }
49
+ return false;
50
+ }
51
+ // ---------------------------------------------------------------------------
52
+ // Factory
53
+ // ---------------------------------------------------------------------------
54
+ /**
55
+ * Create a content pipeline instance.
56
+ *
57
+ * The pipeline manages a priority-ordered set of content handlers and routes
58
+ * incoming content items through them. All operations dispatched by handlers
59
+ * are buffered and flushed as a single engine.dispatch() call, ensuring each
60
+ * paste/drop is a single undo group.
61
+ *
62
+ * @returns A new ContentPipeline instance
63
+ *
64
+ * @example
65
+ * ```ts
66
+ * const pipeline = createContentPipeline();
67
+ * pipeline.register(createPlainTextHandler(() => generateId()));
68
+ * ```
69
+ */
70
+ export function createContentPipeline() {
71
+ let handlers = [];
72
+ const eventListeners = new Set();
73
+ let destroyed = false;
74
+ /**
75
+ * Get handlers sorted by descending priority (higher runs first).
76
+ */
77
+ function getSortedHandlers() {
78
+ return [...handlers].sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
79
+ }
80
+ /**
81
+ * Emit a pipeline event to all listeners.
82
+ */
83
+ function emit(event) {
84
+ for (const listener of eventListeners) {
85
+ try {
86
+ listener(event);
87
+ }
88
+ catch {
89
+ // Event listener errors must not break the pipeline
90
+ }
91
+ }
92
+ }
93
+ /**
94
+ * Create a ContentContext that buffers operations for a single process() call.
95
+ */
96
+ function createContext(opts) {
97
+ const opsBuffer = [];
98
+ let selectionDeleted = false;
99
+ // Compute insert offset: dropOffset takes precedence, otherwise use selection
100
+ const sel = opts.engine.state.selection;
101
+ const insertOffset = opts.dropOffset !== undefined
102
+ ? opts.dropOffset
103
+ : Math.min(sel.anchor.offset, sel.focus.offset);
104
+ const context = {
105
+ engine: opts.engine,
106
+ commands: opts.commands,
107
+ insertOffset,
108
+ source: opts.source,
109
+ deleteSelectionAndGetOffset() {
110
+ if (selectionDeleted)
111
+ return insertOffset;
112
+ selectionDeleted = true;
113
+ const currentSel = opts.engine.state.selection;
114
+ const doc = opts.engine.state.doc;
115
+ const deleteOps = deleteSelectionOps(doc, currentSel);
116
+ if (deleteOps.length > 0) {
117
+ opsBuffer.push(...deleteOps);
118
+ }
119
+ return insertOffset;
120
+ },
121
+ dispatch(ops) {
122
+ opsBuffer.push(...ops);
123
+ },
124
+ generateBlockId() {
125
+ return opts.generateBlockId();
126
+ },
127
+ };
128
+ return { context, getBufferedOps: () => opsBuffer };
129
+ }
130
+ const pipeline = {
131
+ register(handler) {
132
+ if (destroyed) {
133
+ return { dispose: () => { } };
134
+ }
135
+ handlers.push(handler);
136
+ return {
137
+ dispose() {
138
+ handlers = handlers.filter((h) => h !== handler);
139
+ },
140
+ };
141
+ },
142
+ async process(items, contextOpts) {
143
+ if (destroyed || items.length === 0)
144
+ return false;
145
+ // Emit contentReceived event (allows cancellation)
146
+ const receivedEvent = {
147
+ type: 'contentReceived',
148
+ items,
149
+ source: contextOpts.source,
150
+ prevented: false,
151
+ preventDefault() {
152
+ this.prevented = true;
153
+ },
154
+ };
155
+ emit(receivedEvent);
156
+ if (receivedEvent.prevented)
157
+ return false;
158
+ const sorted = getSortedHandlers();
159
+ const { context, getBufferedOps } = createContext(contextOpts);
160
+ // Handler-first iteration: for each handler, check each item
161
+ for (const handler of sorted) {
162
+ for (const item of items) {
163
+ // Check MIME type match
164
+ if (!matchesMime(item.type, handler.accept))
165
+ continue;
166
+ // Optional canHandle check
167
+ if (handler.canHandle) {
168
+ try {
169
+ const can = await handler.canHandle(item, context);
170
+ if (!can)
171
+ continue;
172
+ }
173
+ catch {
174
+ // canHandle errors skip this handler
175
+ continue;
176
+ }
177
+ }
178
+ // Try to handle
179
+ try {
180
+ const handled = await handler.handle(item, context);
181
+ if (handled) {
182
+ // Flush all buffered ops as a single dispatch
183
+ const allOps = getBufferedOps();
184
+ if (allOps.length > 0) {
185
+ contextOpts.engine.dispatch(allOps);
186
+ }
187
+ // Emit contentHandled
188
+ emit({
189
+ type: 'contentHandled',
190
+ handlerId: handler.id,
191
+ item,
192
+ });
193
+ return true;
194
+ }
195
+ }
196
+ catch {
197
+ // handler.handle() errors skip this handler+item pair
198
+ continue;
199
+ }
200
+ }
201
+ }
202
+ // No handler accepted any item — emit contentRejected for each
203
+ for (const item of items) {
204
+ const hasMatchingHandler = sorted.some((h) => matchesMime(item.type, h.accept));
205
+ emit({
206
+ type: 'contentRejected',
207
+ item,
208
+ reason: hasMatchingHandler ? 'all-declined' : 'no-handler',
209
+ });
210
+ }
211
+ return false;
212
+ },
213
+ hasHandlerForType(type) {
214
+ if (destroyed)
215
+ return false;
216
+ return handlers.some((h) => matchesMime(type, h.accept));
217
+ },
218
+ onEvent(listener) {
219
+ eventListeners.add(listener);
220
+ return () => {
221
+ eventListeners.delete(listener);
222
+ };
223
+ },
224
+ destroy() {
225
+ destroyed = true;
226
+ handlers = [];
227
+ eventListeners.clear();
228
+ },
229
+ };
230
+ return pipeline;
231
+ }
232
+ //# sourceMappingURL=content-pipeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-pipeline.js","sourceRoot":"","sources":["../src/content-pipeline.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,149 @@
1
+ /**
2
+ * Keyboard navigation handler for the RTIF web editor.
3
+ *
4
+ * Handles `keydown` events for:
5
+ * - Undo / redo (Cmd+Z, Cmd+Shift+Z / Ctrl+Z, Ctrl+Y)
6
+ * - Select all (Cmd+A / Ctrl+A)
7
+ * - Document-level cursor movement (Cmd+Home/End, Cmd+Up/Down)
8
+ * - Document-level selection extension (Cmd+Shift+Home/End, Cmd+Shift+Up/Down)
9
+ *
10
+ * Arrow keys, word-level movement, and Home/End within a line are delegated
11
+ * to the browser's native `contenteditable` behavior. The `selectionchange`
12
+ * event (handled by selection-sync) reads the resulting DOM selection back
13
+ * into RTIF.
14
+ *
15
+ * @see docs/spec/platform-requirements.md sections 2, 3, and 5
16
+ */
17
+ import type { Document, Selection, Operation } from '@rtif-sdk/core';
18
+ /**
19
+ * Detect whether the current platform is macOS or iOS.
20
+ *
21
+ * Uses `navigator.platform` with a fallback for iPad Safari (which reports
22
+ * `"MacIntel"` but has touch support).
23
+ *
24
+ * @returns `true` on Apple platforms, `false` otherwise
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * if (isMac()) {
29
+ * // Use metaKey for keyboard shortcuts
30
+ * }
31
+ * ```
32
+ */
33
+ export declare function isMac(): boolean;
34
+ /**
35
+ * Check whether the platform modifier key is pressed.
36
+ *
37
+ * On macOS/iOS this is the Meta (Command) key; on other platforms it is
38
+ * the Control key.
39
+ *
40
+ * @param e - The keyboard event to inspect
41
+ * @returns `true` if the platform modifier key is held
42
+ *
43
+ * @example
44
+ * ```ts
45
+ * element.addEventListener('keydown', (e) => {
46
+ * if (isModKey(e) && e.key === 'z') {
47
+ * // undo
48
+ * }
49
+ * });
50
+ * ```
51
+ */
52
+ export declare function isModKey(e: KeyboardEvent): boolean;
53
+ /**
54
+ * Dependencies injected into {@link CursorNavHandler}.
55
+ *
56
+ * @example
57
+ * ```ts
58
+ * const deps: CursorNavDeps = {
59
+ * getSelection: () => engine.state.selection,
60
+ * getDoc: () => engine.state.doc,
61
+ * dispatch: (ops) => engine.dispatch(ops),
62
+ * undo: () => engine.undo(),
63
+ * redo: () => engine.redo(),
64
+ * isComposing: () => compositionHandler.isComposing(),
65
+ * isReadOnly: () => config.readOnly ?? false,
66
+ * setSelection: (sel) => { ... },
67
+ * isMac: () => isMac(),
68
+ * };
69
+ * ```
70
+ */
71
+ export interface CursorNavDeps {
72
+ /** Return the current RTIF selection. */
73
+ readonly getSelection: () => Selection;
74
+ /** Return the current RTIF document. */
75
+ readonly getDoc: () => Document;
76
+ /** Dispatch one or more RTIF operations to the engine. */
77
+ readonly dispatch: (ops: Operation | Operation[]) => void;
78
+ /** Trigger undo on the engine. */
79
+ readonly undo: () => void;
80
+ /** Trigger redo on the engine. */
81
+ readonly redo: () => void;
82
+ /** Whether an IME composition session is active. */
83
+ readonly isComposing: () => boolean;
84
+ /** Whether the editor is in read-only mode. */
85
+ readonly isReadOnly: () => boolean;
86
+ /**
87
+ * Update the RTIF selection without dispatching an operation.
88
+ * This triggers DOM selection sync and onChange notification.
89
+ */
90
+ readonly setSelection: (selection: Selection) => void;
91
+ /** Whether the current platform is macOS/iOS. */
92
+ readonly isMac: () => boolean;
93
+ }
94
+ /**
95
+ * Handles `keydown` events for keyboard shortcuts and document-level
96
+ * cursor navigation.
97
+ *
98
+ * The handler intercepts:
99
+ * - **Undo/redo**: Cmd+Z, Cmd+Shift+Z (Mac) / Ctrl+Z, Ctrl+Y (Win/Linux)
100
+ * - **Select all**: Cmd+A / Ctrl+A
101
+ * - **Document start/end**: Cmd+Home, Cmd+End, Cmd+Up, Cmd+Down (Mac)
102
+ * - **Selection to document edges**: Cmd+Shift+Home/End/Up/Down
103
+ *
104
+ * All other key events (including arrow keys, Home/End without Cmd,
105
+ * word-level movement) are left to the browser's native contenteditable
106
+ * handling. The selection-sync module reads the resulting DOM selection
107
+ * back into RTIF via `selectionchange`.
108
+ *
109
+ * @example
110
+ * ```ts
111
+ * const handler = new CursorNavHandler(root, deps);
112
+ * handler.attach();
113
+ * // ... later ...
114
+ * handler.detach();
115
+ * ```
116
+ */
117
+ export declare class CursorNavHandler {
118
+ private readonly _root;
119
+ private readonly _deps;
120
+ private _keydownHandler;
121
+ constructor(root: HTMLElement, deps: CursorNavDeps);
122
+ /**
123
+ * Attach the `keydown` event listener to the root element.
124
+ *
125
+ * @example
126
+ * ```ts
127
+ * handler.attach();
128
+ * ```
129
+ */
130
+ attach(): void;
131
+ /**
132
+ * Remove the `keydown` event listener from the root element.
133
+ *
134
+ * @example
135
+ * ```ts
136
+ * handler.detach();
137
+ * ```
138
+ */
139
+ detach(): void;
140
+ private _onKeydown;
141
+ /**
142
+ * Handle Cmd/Ctrl + Home/End/ArrowUp/ArrowDown for document-level navigation.
143
+ *
144
+ * Returns `true` if the event was handled (and preventDefault was called),
145
+ * `false` if the event should be left to the browser.
146
+ */
147
+ private _handleDocumentNav;
148
+ }
149
+ //# sourceMappingURL=cursor-nav.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor-nav.d.ts","sourceRoot":"","sources":["../src/cursor-nav.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAOrE;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,KAAK,IAAI,OAAO,CAM/B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,aAAa,GAAG,OAAO,CAElD;AAMD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,aAAa;IAC5B,yCAAyC;IACzC,QAAQ,CAAC,YAAY,EAAE,MAAM,SAAS,CAAC;IAEvC,wCAAwC;IACxC,QAAQ,CAAC,MAAM,EAAE,MAAM,QAAQ,CAAC;IAEhC,0DAA0D;IAC1D,QAAQ,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,SAAS,GAAG,SAAS,EAAE,KAAK,IAAI,CAAC;IAE1D,kCAAkC;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,IAAI,CAAC;IAE1B,kCAAkC;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,IAAI,CAAC;IAE1B,oDAAoD;IACpD,QAAQ,CAAC,WAAW,EAAE,MAAM,OAAO,CAAC;IAEpC,+CAA+C;IAC/C,QAAQ,CAAC,UAAU,EAAE,MAAM,OAAO,CAAC;IAEnC;;;OAGG;IACH,QAAQ,CAAC,YAAY,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,IAAI,CAAC;IAEtD,iDAAiD;IACjD,QAAQ,CAAC,KAAK,EAAE,MAAM,OAAO,CAAC;CAC/B;AAMD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAc;IACpC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgB;IACtC,OAAO,CAAC,eAAe,CAA6C;gBAExD,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,aAAa;IAKlD;;;;;;;OAOG;IACH,MAAM,IAAI,IAAI;IAKd;;;;;;;OAOG;IACH,MAAM,IAAI,IAAI;IAWd,OAAO,CAAC,UAAU;IAuDlB;;;;;OAKG;IACH,OAAO,CAAC,kBAAkB;CA6C3B"}
@@ -0,0 +1,230 @@
1
+ /**
2
+ * Keyboard navigation handler for the RTIF web editor.
3
+ *
4
+ * Handles `keydown` events for:
5
+ * - Undo / redo (Cmd+Z, Cmd+Shift+Z / Ctrl+Z, Ctrl+Y)
6
+ * - Select all (Cmd+A / Ctrl+A)
7
+ * - Document-level cursor movement (Cmd+Home/End, Cmd+Up/Down)
8
+ * - Document-level selection extension (Cmd+Shift+Home/End, Cmd+Shift+Up/Down)
9
+ *
10
+ * Arrow keys, word-level movement, and Home/End within a line are delegated
11
+ * to the browser's native `contenteditable` behavior. The `selectionchange`
12
+ * event (handled by selection-sync) reads the resulting DOM selection back
13
+ * into RTIF.
14
+ *
15
+ * @see docs/spec/platform-requirements.md sections 2, 3, and 5
16
+ */
17
+ import { docLength } from '@rtif-sdk/core';
18
+ // ---------------------------------------------------------------------------
19
+ // Platform detection
20
+ // ---------------------------------------------------------------------------
21
+ /**
22
+ * Detect whether the current platform is macOS or iOS.
23
+ *
24
+ * Uses `navigator.platform` with a fallback for iPad Safari (which reports
25
+ * `"MacIntel"` but has touch support).
26
+ *
27
+ * @returns `true` on Apple platforms, `false` otherwise
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * if (isMac()) {
32
+ * // Use metaKey for keyboard shortcuts
33
+ * }
34
+ * ```
35
+ */
36
+ export function isMac() {
37
+ if (typeof navigator === 'undefined')
38
+ return false;
39
+ return /Mac|iPod|iPhone|iPad/.test(navigator.platform)
40
+ || (navigator.platform === 'MacIntel'
41
+ && typeof navigator.maxTouchPoints === 'number'
42
+ && navigator.maxTouchPoints > 1);
43
+ }
44
+ /**
45
+ * Check whether the platform modifier key is pressed.
46
+ *
47
+ * On macOS/iOS this is the Meta (Command) key; on other platforms it is
48
+ * the Control key.
49
+ *
50
+ * @param e - The keyboard event to inspect
51
+ * @returns `true` if the platform modifier key is held
52
+ *
53
+ * @example
54
+ * ```ts
55
+ * element.addEventListener('keydown', (e) => {
56
+ * if (isModKey(e) && e.key === 'z') {
57
+ * // undo
58
+ * }
59
+ * });
60
+ * ```
61
+ */
62
+ export function isModKey(e) {
63
+ return isMac() ? e.metaKey : e.ctrlKey;
64
+ }
65
+ // ---------------------------------------------------------------------------
66
+ // CursorNavHandler class
67
+ // ---------------------------------------------------------------------------
68
+ /**
69
+ * Handles `keydown` events for keyboard shortcuts and document-level
70
+ * cursor navigation.
71
+ *
72
+ * The handler intercepts:
73
+ * - **Undo/redo**: Cmd+Z, Cmd+Shift+Z (Mac) / Ctrl+Z, Ctrl+Y (Win/Linux)
74
+ * - **Select all**: Cmd+A / Ctrl+A
75
+ * - **Document start/end**: Cmd+Home, Cmd+End, Cmd+Up, Cmd+Down (Mac)
76
+ * - **Selection to document edges**: Cmd+Shift+Home/End/Up/Down
77
+ *
78
+ * All other key events (including arrow keys, Home/End without Cmd,
79
+ * word-level movement) are left to the browser's native contenteditable
80
+ * handling. The selection-sync module reads the resulting DOM selection
81
+ * back into RTIF via `selectionchange`.
82
+ *
83
+ * @example
84
+ * ```ts
85
+ * const handler = new CursorNavHandler(root, deps);
86
+ * handler.attach();
87
+ * // ... later ...
88
+ * handler.detach();
89
+ * ```
90
+ */
91
+ export class CursorNavHandler {
92
+ _root;
93
+ _deps;
94
+ _keydownHandler = null;
95
+ constructor(root, deps) {
96
+ this._root = root;
97
+ this._deps = deps;
98
+ }
99
+ /**
100
+ * Attach the `keydown` event listener to the root element.
101
+ *
102
+ * @example
103
+ * ```ts
104
+ * handler.attach();
105
+ * ```
106
+ */
107
+ attach() {
108
+ this._keydownHandler = (e) => this._onKeydown(e);
109
+ this._root.addEventListener('keydown', this._keydownHandler);
110
+ }
111
+ /**
112
+ * Remove the `keydown` event listener from the root element.
113
+ *
114
+ * @example
115
+ * ```ts
116
+ * handler.detach();
117
+ * ```
118
+ */
119
+ detach() {
120
+ if (this._keydownHandler) {
121
+ this._root.removeEventListener('keydown', this._keydownHandler);
122
+ this._keydownHandler = null;
123
+ }
124
+ }
125
+ // -----------------------------------------------------------------------
126
+ // Keydown dispatcher
127
+ // -----------------------------------------------------------------------
128
+ _onKeydown(e) {
129
+ // Never interfere with IME composition
130
+ if (this._deps.isComposing())
131
+ return;
132
+ const mod = this._deps.isMac() ? e.metaKey : e.ctrlKey;
133
+ // --- Undo: Cmd+Z / Ctrl+Z (no shift, no alt) ---
134
+ if (mod && !e.shiftKey && !e.altKey && e.key === 'z') {
135
+ e.preventDefault();
136
+ this._deps.undo();
137
+ return;
138
+ }
139
+ // --- Redo: Cmd+Shift+Z (Mac) / Ctrl+Y (Win/Linux) ---
140
+ if (this._deps.isMac()) {
141
+ if (e.metaKey && e.shiftKey && !e.altKey && e.key === 'z') {
142
+ e.preventDefault();
143
+ this._deps.redo();
144
+ return;
145
+ }
146
+ }
147
+ else {
148
+ if (e.ctrlKey && !e.shiftKey && !e.altKey && e.key === 'y') {
149
+ e.preventDefault();
150
+ this._deps.redo();
151
+ return;
152
+ }
153
+ // Also support Ctrl+Shift+Z on non-Mac
154
+ if (e.ctrlKey && e.shiftKey && !e.altKey && e.key === 'z') {
155
+ e.preventDefault();
156
+ this._deps.redo();
157
+ return;
158
+ }
159
+ }
160
+ // --- Select all: Cmd+A / Ctrl+A ---
161
+ if (mod && !e.shiftKey && !e.altKey && e.key === 'a') {
162
+ e.preventDefault();
163
+ const doc = this._deps.getDoc();
164
+ const len = docLength(doc);
165
+ this._deps.setSelection({
166
+ anchor: { offset: 0 },
167
+ focus: { offset: len },
168
+ });
169
+ return;
170
+ }
171
+ // --- Document-level navigation ---
172
+ // These handle Cmd+Home/End and Cmd+Up/Down (Mac equivalents).
173
+ // With Shift held, they extend selection instead of moving cursor.
174
+ if (mod && !e.altKey) {
175
+ if (this._handleDocumentNav(e))
176
+ return;
177
+ }
178
+ }
179
+ /**
180
+ * Handle Cmd/Ctrl + Home/End/ArrowUp/ArrowDown for document-level navigation.
181
+ *
182
+ * Returns `true` if the event was handled (and preventDefault was called),
183
+ * `false` if the event should be left to the browser.
184
+ */
185
+ _handleDocumentNav(e) {
186
+ const doc = this._deps.getDoc();
187
+ const len = docLength(doc);
188
+ const sel = this._deps.getSelection();
189
+ // Move to document start
190
+ if (e.key === 'Home' || (this._deps.isMac() && e.key === 'ArrowUp')) {
191
+ e.preventDefault();
192
+ if (e.shiftKey) {
193
+ // Extend selection: keep anchor, move focus to 0
194
+ this._deps.setSelection({
195
+ anchor: sel.anchor,
196
+ focus: { offset: 0 },
197
+ });
198
+ }
199
+ else {
200
+ // Collapse cursor to document start
201
+ this._deps.setSelection({
202
+ anchor: { offset: 0 },
203
+ focus: { offset: 0 },
204
+ });
205
+ }
206
+ return true;
207
+ }
208
+ // Move to document end
209
+ if (e.key === 'End' || (this._deps.isMac() && e.key === 'ArrowDown')) {
210
+ e.preventDefault();
211
+ if (e.shiftKey) {
212
+ // Extend selection: keep anchor, move focus to end
213
+ this._deps.setSelection({
214
+ anchor: sel.anchor,
215
+ focus: { offset: len },
216
+ });
217
+ }
218
+ else {
219
+ // Collapse cursor to document end
220
+ this._deps.setSelection({
221
+ anchor: { offset: len },
222
+ focus: { offset: len },
223
+ });
224
+ }
225
+ return true;
226
+ }
227
+ return false;
228
+ }
229
+ }
230
+ //# sourceMappingURL=cursor-nav.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor-nav.js","sourceRoot":"","sources":["../src/cursor-nav.ts"],"names":[],"mappings":"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"}