@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.
- package/LICENSE +21 -0
- package/README.md +67 -0
- package/dist/block-drag-handler.d.ts +189 -0
- package/dist/block-drag-handler.d.ts.map +1 -0
- package/dist/block-drag-handler.js +745 -0
- package/dist/block-drag-handler.js.map +1 -0
- package/dist/block-renderer.d.ts +402 -0
- package/dist/block-renderer.d.ts.map +1 -0
- package/dist/block-renderer.js +424 -0
- package/dist/block-renderer.js.map +1 -0
- package/dist/clipboard.d.ts +178 -0
- package/dist/clipboard.d.ts.map +1 -0
- package/dist/clipboard.js +432 -0
- package/dist/clipboard.js.map +1 -0
- package/dist/command-bus.d.ts +113 -0
- package/dist/command-bus.d.ts.map +1 -0
- package/dist/command-bus.js +70 -0
- package/dist/command-bus.js.map +1 -0
- package/dist/composition.d.ts +220 -0
- package/dist/composition.d.ts.map +1 -0
- package/dist/composition.js +271 -0
- package/dist/composition.js.map +1 -0
- package/dist/content-extraction.d.ts +69 -0
- package/dist/content-extraction.d.ts.map +1 -0
- package/dist/content-extraction.js +228 -0
- package/dist/content-extraction.js.map +1 -0
- package/dist/content-handler-file.d.ts +40 -0
- package/dist/content-handler-file.d.ts.map +1 -0
- package/dist/content-handler-file.js +91 -0
- package/dist/content-handler-file.js.map +1 -0
- package/dist/content-handler-image.d.ts +82 -0
- package/dist/content-handler-image.d.ts.map +1 -0
- package/dist/content-handler-image.js +120 -0
- package/dist/content-handler-image.js.map +1 -0
- package/dist/content-handler-url.d.ts +129 -0
- package/dist/content-handler-url.d.ts.map +1 -0
- package/dist/content-handler-url.js +244 -0
- package/dist/content-handler-url.js.map +1 -0
- package/dist/content-handlers.d.ts +67 -0
- package/dist/content-handlers.d.ts.map +1 -0
- package/dist/content-handlers.js +263 -0
- package/dist/content-handlers.js.map +1 -0
- package/dist/content-pipeline.d.ts +383 -0
- package/dist/content-pipeline.d.ts.map +1 -0
- package/dist/content-pipeline.js +232 -0
- package/dist/content-pipeline.js.map +1 -0
- package/dist/cursor-nav.d.ts +149 -0
- package/dist/cursor-nav.d.ts.map +1 -0
- package/dist/cursor-nav.js +230 -0
- package/dist/cursor-nav.js.map +1 -0
- package/dist/cursor-rect.d.ts +65 -0
- package/dist/cursor-rect.d.ts.map +1 -0
- package/dist/cursor-rect.js +98 -0
- package/dist/cursor-rect.js.map +1 -0
- package/dist/drop-indicator.d.ts +108 -0
- package/dist/drop-indicator.d.ts.map +1 -0
- package/dist/drop-indicator.js +236 -0
- package/dist/drop-indicator.js.map +1 -0
- package/dist/editor.d.ts +41 -0
- package/dist/editor.d.ts.map +1 -0
- package/dist/editor.js +710 -0
- package/dist/editor.js.map +1 -0
- package/dist/floating-toolbar.d.ts +93 -0
- package/dist/floating-toolbar.d.ts.map +1 -0
- package/dist/floating-toolbar.js +159 -0
- package/dist/floating-toolbar.js.map +1 -0
- package/dist/index.d.ts +62 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +119 -0
- package/dist/index.js.map +1 -0
- package/dist/input-bridge.d.ts +273 -0
- package/dist/input-bridge.d.ts.map +1 -0
- package/dist/input-bridge.js +884 -0
- package/dist/input-bridge.js.map +1 -0
- package/dist/link-popover.d.ts +38 -0
- package/dist/link-popover.d.ts.map +1 -0
- package/dist/link-popover.js +278 -0
- package/dist/link-popover.js.map +1 -0
- package/dist/mark-renderer.d.ts +275 -0
- package/dist/mark-renderer.d.ts.map +1 -0
- package/dist/mark-renderer.js +210 -0
- package/dist/mark-renderer.js.map +1 -0
- package/dist/perf.d.ts +145 -0
- package/dist/perf.d.ts.map +1 -0
- package/dist/perf.js +260 -0
- package/dist/perf.js.map +1 -0
- package/dist/plugin-kit.d.ts +265 -0
- package/dist/plugin-kit.d.ts.map +1 -0
- package/dist/plugin-kit.js +234 -0
- package/dist/plugin-kit.js.map +1 -0
- package/dist/plugins/alignment-plugin.d.ts +68 -0
- package/dist/plugins/alignment-plugin.d.ts.map +1 -0
- package/dist/plugins/alignment-plugin.js +98 -0
- package/dist/plugins/alignment-plugin.js.map +1 -0
- package/dist/plugins/block-utils.d.ts +113 -0
- package/dist/plugins/block-utils.d.ts.map +1 -0
- package/dist/plugins/block-utils.js +191 -0
- package/dist/plugins/block-utils.js.map +1 -0
- package/dist/plugins/blockquote-plugin.d.ts +39 -0
- package/dist/plugins/blockquote-plugin.d.ts.map +1 -0
- package/dist/plugins/blockquote-plugin.js +88 -0
- package/dist/plugins/blockquote-plugin.js.map +1 -0
- package/dist/plugins/bold-plugin.d.ts +37 -0
- package/dist/plugins/bold-plugin.d.ts.map +1 -0
- package/dist/plugins/bold-plugin.js +48 -0
- package/dist/plugins/bold-plugin.js.map +1 -0
- package/dist/plugins/callout-plugin.d.ts +100 -0
- package/dist/plugins/callout-plugin.d.ts.map +1 -0
- package/dist/plugins/callout-plugin.js +200 -0
- package/dist/plugins/callout-plugin.js.map +1 -0
- package/dist/plugins/code-block-plugin.d.ts +62 -0
- package/dist/plugins/code-block-plugin.d.ts.map +1 -0
- package/dist/plugins/code-block-plugin.js +176 -0
- package/dist/plugins/code-block-plugin.js.map +1 -0
- package/dist/plugins/code-plugin.d.ts +37 -0
- package/dist/plugins/code-plugin.d.ts.map +1 -0
- package/dist/plugins/code-plugin.js +48 -0
- package/dist/plugins/code-plugin.js.map +1 -0
- package/dist/plugins/embed-plugin.d.ts +90 -0
- package/dist/plugins/embed-plugin.d.ts.map +1 -0
- package/dist/plugins/embed-plugin.js +147 -0
- package/dist/plugins/embed-plugin.js.map +1 -0
- package/dist/plugins/font-family-plugin.d.ts +58 -0
- package/dist/plugins/font-family-plugin.d.ts.map +1 -0
- package/dist/plugins/font-family-plugin.js +57 -0
- package/dist/plugins/font-family-plugin.js.map +1 -0
- package/dist/plugins/font-size-plugin.d.ts +57 -0
- package/dist/plugins/font-size-plugin.d.ts.map +1 -0
- package/dist/plugins/font-size-plugin.js +56 -0
- package/dist/plugins/font-size-plugin.js.map +1 -0
- package/dist/plugins/heading-plugin.d.ts +52 -0
- package/dist/plugins/heading-plugin.d.ts.map +1 -0
- package/dist/plugins/heading-plugin.js +114 -0
- package/dist/plugins/heading-plugin.js.map +1 -0
- package/dist/plugins/hr-plugin.d.ts +33 -0
- package/dist/plugins/hr-plugin.d.ts.map +1 -0
- package/dist/plugins/hr-plugin.js +75 -0
- package/dist/plugins/hr-plugin.js.map +1 -0
- package/dist/plugins/image-plugin.d.ts +115 -0
- package/dist/plugins/image-plugin.d.ts.map +1 -0
- package/dist/plugins/image-plugin.js +199 -0
- package/dist/plugins/image-plugin.js.map +1 -0
- package/dist/plugins/indent-plugin.d.ts +62 -0
- package/dist/plugins/indent-plugin.d.ts.map +1 -0
- package/dist/plugins/indent-plugin.js +128 -0
- package/dist/plugins/indent-plugin.js.map +1 -0
- package/dist/plugins/index.d.ts +45 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +42 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/italic-plugin.d.ts +37 -0
- package/dist/plugins/italic-plugin.d.ts.map +1 -0
- package/dist/plugins/italic-plugin.js +48 -0
- package/dist/plugins/italic-plugin.js.map +1 -0
- package/dist/plugins/link-plugin.d.ts +129 -0
- package/dist/plugins/link-plugin.d.ts.map +1 -0
- package/dist/plugins/link-plugin.js +212 -0
- package/dist/plugins/link-plugin.js.map +1 -0
- package/dist/plugins/list-plugin.d.ts +53 -0
- package/dist/plugins/list-plugin.d.ts.map +1 -0
- package/dist/plugins/list-plugin.js +309 -0
- package/dist/plugins/list-plugin.js.map +1 -0
- package/dist/plugins/mark-utils.d.ts +173 -0
- package/dist/plugins/mark-utils.d.ts.map +1 -0
- package/dist/plugins/mark-utils.js +425 -0
- package/dist/plugins/mark-utils.js.map +1 -0
- package/dist/plugins/mention-plugin.d.ts +191 -0
- package/dist/plugins/mention-plugin.d.ts.map +1 -0
- package/dist/plugins/mention-plugin.js +295 -0
- package/dist/plugins/mention-plugin.js.map +1 -0
- package/dist/plugins/strikethrough-plugin.d.ts +37 -0
- package/dist/plugins/strikethrough-plugin.d.ts.map +1 -0
- package/dist/plugins/strikethrough-plugin.js +48 -0
- package/dist/plugins/strikethrough-plugin.js.map +1 -0
- package/dist/plugins/text-color-plugin.d.ts +57 -0
- package/dist/plugins/text-color-plugin.d.ts.map +1 -0
- package/dist/plugins/text-color-plugin.js +56 -0
- package/dist/plugins/text-color-plugin.js.map +1 -0
- package/dist/plugins/underline-plugin.d.ts +37 -0
- package/dist/plugins/underline-plugin.d.ts.map +1 -0
- package/dist/plugins/underline-plugin.js +48 -0
- package/dist/plugins/underline-plugin.js.map +1 -0
- package/dist/presets.d.ts +95 -0
- package/dist/presets.d.ts.map +1 -0
- package/dist/presets.js +159 -0
- package/dist/presets.js.map +1 -0
- package/dist/renderer.d.ts +125 -0
- package/dist/renderer.d.ts.map +1 -0
- package/dist/renderer.js +415 -0
- package/dist/renderer.js.map +1 -0
- package/dist/scroll-to-cursor.d.ts +25 -0
- package/dist/scroll-to-cursor.d.ts.map +1 -0
- package/dist/scroll-to-cursor.js +59 -0
- package/dist/scroll-to-cursor.js.map +1 -0
- package/dist/selection-sync.d.ts +159 -0
- package/dist/selection-sync.d.ts.map +1 -0
- package/dist/selection-sync.js +527 -0
- package/dist/selection-sync.js.map +1 -0
- package/dist/shortcut-handler.d.ts +98 -0
- package/dist/shortcut-handler.d.ts.map +1 -0
- package/dist/shortcut-handler.js +155 -0
- package/dist/shortcut-handler.js.map +1 -0
- package/dist/toolbar.d.ts +103 -0
- package/dist/toolbar.d.ts.map +1 -0
- package/dist/toolbar.js +134 -0
- package/dist/toolbar.js.map +1 -0
- package/dist/trigger-manager.d.ts +205 -0
- package/dist/trigger-manager.d.ts.map +1 -0
- package/dist/trigger-manager.js +466 -0
- package/dist/trigger-manager.js.map +1 -0
- package/dist/types.d.ts +216 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +30 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IME composition state machine for the RTIF web editor.
|
|
3
|
+
*
|
|
4
|
+
* During composition (CJK input, accent dead keys, dictation, emoji picker),
|
|
5
|
+
* the browser owns the DOM in the composing block. RTIF operations are NOT
|
|
6
|
+
* dispatched and the composing block is NOT reconciled until the composition
|
|
7
|
+
* session ends. On commit, a single {@link CompositionCommit} is returned
|
|
8
|
+
* so the caller can dispatch the appropriate RTIF operations.
|
|
9
|
+
*
|
|
10
|
+
* State machine:
|
|
11
|
+
* ```
|
|
12
|
+
* IDLE --compositionstart--> COMPOSING --compositionend--> IDLE
|
|
13
|
+
* | |
|
|
14
|
+
* (browser renders preview) (commit RTIF ops)
|
|
15
|
+
* (no RTIF ops dispatched)
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* @module
|
|
19
|
+
*/
|
|
20
|
+
import type { Selection } from '@rtif-sdk/core';
|
|
21
|
+
import type { CompositionState } from './types.js';
|
|
22
|
+
/**
|
|
23
|
+
* The result of a completed composition session.
|
|
24
|
+
*
|
|
25
|
+
* Returned by {@link CompositionHandler.onCompositionEnd} when the user
|
|
26
|
+
* commits text. The caller is responsible for dispatching the corresponding
|
|
27
|
+
* RTIF operations (delete selection range if present, then insert text).
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```ts
|
|
31
|
+
* const commit = compositionHandler.onCompositionEnd(event);
|
|
32
|
+
* if (commit) {
|
|
33
|
+
* if (commit.deleteRange) {
|
|
34
|
+
* engine.dispatch({ type: 'delete_text', offset: commit.deleteRange.offset, count: commit.deleteRange.count });
|
|
35
|
+
* }
|
|
36
|
+
* engine.dispatch({ type: 'insert_text', offset: commit.offset, text: commit.text });
|
|
37
|
+
* }
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export interface CompositionCommit {
|
|
41
|
+
/** The committed text from the composition session. */
|
|
42
|
+
readonly text: string;
|
|
43
|
+
/** The absolute document offset where the text should be inserted. */
|
|
44
|
+
readonly offset: number;
|
|
45
|
+
/**
|
|
46
|
+
* If the user had a non-collapsed selection when composition started,
|
|
47
|
+
* this range should be deleted before inserting the committed text.
|
|
48
|
+
* Deletion happens on commit, not on start, to avoid breaking IME.
|
|
49
|
+
*/
|
|
50
|
+
readonly deleteRange: {
|
|
51
|
+
readonly offset: number;
|
|
52
|
+
readonly count: number;
|
|
53
|
+
} | null;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Dependencies injected into the {@link CompositionHandler}.
|
|
57
|
+
*
|
|
58
|
+
* These callbacks allow the handler to read editor state without
|
|
59
|
+
* depending directly on the engine or DOM.
|
|
60
|
+
*/
|
|
61
|
+
export interface CompositionDeps {
|
|
62
|
+
/**
|
|
63
|
+
* Return the current RTIF selection from the engine, or null if
|
|
64
|
+
* the editor has no selection (e.g. during initialization).
|
|
65
|
+
*/
|
|
66
|
+
readonly getSelection: () => Selection | null;
|
|
67
|
+
/**
|
|
68
|
+
* Resolve an absolute document offset to the block ID at that position.
|
|
69
|
+
* Returns null if the offset cannot be resolved.
|
|
70
|
+
*
|
|
71
|
+
* @param offset - Absolute document offset
|
|
72
|
+
*/
|
|
73
|
+
readonly getBlockIdAtOffset: (offset: number) => string | null;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Manages IME composition state for the RTIF web editor.
|
|
77
|
+
*
|
|
78
|
+
* Attach the three `onComposition*` methods to the corresponding DOM events
|
|
79
|
+
* on the contenteditable element. The handler tracks whether a composition
|
|
80
|
+
* session is active and produces a {@link CompositionCommit} when the session
|
|
81
|
+
* ends with committed text.
|
|
82
|
+
*
|
|
83
|
+
* During `isComposing() === true`:
|
|
84
|
+
* - The InputBridge must NOT dispatch RTIF operations for composition-related
|
|
85
|
+
* `beforeinput` events (`insertCompositionText`, `deleteByComposition`).
|
|
86
|
+
* - The InputBridge must NOT call `preventDefault()` on those events.
|
|
87
|
+
* - The Renderer must NOT reconcile the composing block.
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```ts
|
|
91
|
+
* const handler = new CompositionHandler({
|
|
92
|
+
* getSelection: () => engine.state.selection,
|
|
93
|
+
* getBlockIdAtOffset: (offset) => {
|
|
94
|
+
* const { blockIndex } = resolve(engine.state.doc, offset);
|
|
95
|
+
* return engine.state.doc.blocks[blockIndex]?.id ?? null;
|
|
96
|
+
* },
|
|
97
|
+
* });
|
|
98
|
+
*
|
|
99
|
+
* el.addEventListener('compositionstart', (e) => handler.onCompositionStart(e));
|
|
100
|
+
* el.addEventListener('compositionupdate', (e) => handler.onCompositionUpdate(e));
|
|
101
|
+
* el.addEventListener('compositionend', (e) => {
|
|
102
|
+
* const commit = handler.onCompositionEnd(e);
|
|
103
|
+
* if (commit) {
|
|
104
|
+
* // dispatch RTIF operations from commit
|
|
105
|
+
* }
|
|
106
|
+
* });
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
export declare class CompositionHandler {
|
|
110
|
+
private _composing;
|
|
111
|
+
private _composingBlockId;
|
|
112
|
+
private _startOffset;
|
|
113
|
+
private _selectionRange;
|
|
114
|
+
private readonly _deps;
|
|
115
|
+
constructor(deps: CompositionDeps);
|
|
116
|
+
/**
|
|
117
|
+
* Handle the `compositionstart` DOM event.
|
|
118
|
+
*
|
|
119
|
+
* Enters the composing state. Reads the current RTIF selection to
|
|
120
|
+
* determine where the composition will insert text. If a non-collapsed
|
|
121
|
+
* selection exists, records it so the range can be deleted on commit
|
|
122
|
+
* (not on start, to avoid breaking IME).
|
|
123
|
+
*
|
|
124
|
+
* Does NOT call `preventDefault()` — the browser must be allowed to
|
|
125
|
+
* render its native composition preview.
|
|
126
|
+
*
|
|
127
|
+
* @param _e - The compositionstart event (data not used)
|
|
128
|
+
*/
|
|
129
|
+
onCompositionStart(_e: CompositionEvent): void;
|
|
130
|
+
/**
|
|
131
|
+
* Handle the `compositionupdate` DOM event.
|
|
132
|
+
*
|
|
133
|
+
* This is intentionally a no-op. The browser is rendering its native
|
|
134
|
+
* composition preview and we must not interfere. No RTIF operations
|
|
135
|
+
* are dispatched during composition.
|
|
136
|
+
*
|
|
137
|
+
* @param _e - The compositionupdate event (ignored)
|
|
138
|
+
*/
|
|
139
|
+
onCompositionUpdate(_e: CompositionEvent): void;
|
|
140
|
+
/**
|
|
141
|
+
* Handle the `compositionend` DOM event.
|
|
142
|
+
*
|
|
143
|
+
* Exits the composing state and returns a {@link CompositionCommit}
|
|
144
|
+
* describing the text to insert and any selection range to delete.
|
|
145
|
+
*
|
|
146
|
+
* Returns `null` if:
|
|
147
|
+
* - The committed text (`e.data`) is empty or null (composition cancelled)
|
|
148
|
+
* - No composition was in progress (`compositionstart` was never received)
|
|
149
|
+
* - The start offset is unknown (selection was null at composition start)
|
|
150
|
+
*
|
|
151
|
+
* The caller is responsible for dispatching RTIF operations from the
|
|
152
|
+
* returned commit.
|
|
153
|
+
*
|
|
154
|
+
* @param e - The compositionend event containing the committed text
|
|
155
|
+
* @returns A commit descriptor, or `null` if no operation should be dispatched
|
|
156
|
+
*/
|
|
157
|
+
onCompositionEnd(e: CompositionEvent): CompositionCommit | null;
|
|
158
|
+
/**
|
|
159
|
+
* Whether a composition session is currently active.
|
|
160
|
+
*
|
|
161
|
+
* When `true`, the InputBridge and Renderer must defer to the browser's
|
|
162
|
+
* native composition handling.
|
|
163
|
+
*
|
|
164
|
+
* @returns `true` if between `compositionstart` and `compositionend`
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* ```ts
|
|
168
|
+
* if (compositionHandler.isComposing()) {
|
|
169
|
+
* // Skip RTIF operation dispatch and DOM reconciliation
|
|
170
|
+
* }
|
|
171
|
+
* ```
|
|
172
|
+
*/
|
|
173
|
+
isComposing(): boolean;
|
|
174
|
+
/**
|
|
175
|
+
* The block ID where the current composition is occurring.
|
|
176
|
+
*
|
|
177
|
+
* Used by the Renderer to skip reconciliation of this block during
|
|
178
|
+
* composition. Returns `null` when not composing or when the block
|
|
179
|
+
* could not be resolved.
|
|
180
|
+
*
|
|
181
|
+
* @returns The composing block ID, or `null`
|
|
182
|
+
*
|
|
183
|
+
* @example
|
|
184
|
+
* ```ts
|
|
185
|
+
* const blockId = compositionHandler.getComposingBlockId();
|
|
186
|
+
* reconcile(root, prevDoc, nextDoc, blockId);
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
getComposingBlockId(): string | null;
|
|
190
|
+
/**
|
|
191
|
+
* Return a snapshot of the current composition state.
|
|
192
|
+
*
|
|
193
|
+
* The returned object is a plain value — it will not change when the
|
|
194
|
+
* handler's internal state changes.
|
|
195
|
+
*
|
|
196
|
+
* @returns An immutable snapshot of the composition state
|
|
197
|
+
*
|
|
198
|
+
* @example
|
|
199
|
+
* ```ts
|
|
200
|
+
* const state = compositionHandler.getState();
|
|
201
|
+
* console.log(state.composing, state.composingBlockId);
|
|
202
|
+
* ```
|
|
203
|
+
*/
|
|
204
|
+
getState(): CompositionState;
|
|
205
|
+
/**
|
|
206
|
+
* Force-reset the handler to idle state.
|
|
207
|
+
*
|
|
208
|
+
* Use this when the editor blurs, is destroyed, or needs to abandon
|
|
209
|
+
* a composition session for any reason.
|
|
210
|
+
*
|
|
211
|
+
* @example
|
|
212
|
+
* ```ts
|
|
213
|
+
* el.addEventListener('blur', () => compositionHandler.reset());
|
|
214
|
+
* ```
|
|
215
|
+
*/
|
|
216
|
+
reset(): void;
|
|
217
|
+
/** Clear all internal state to the idle defaults. */
|
|
218
|
+
private _resetInternal;
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=composition.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"composition.d.ts","sourceRoot":"","sources":["../src/composition.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAMnD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,iBAAiB;IAChC,uDAAuD;IACvD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,sEAAsE;IACtE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB;;;;OAIG;IACH,QAAQ,CAAC,WAAW,EAAE;QACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;KACxB,GAAG,IAAI,CAAC;CACV;AAED;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,SAAS,GAAG,IAAI,CAAC;IAE9C;;;;;OAKG;IACH,QAAQ,CAAC,kBAAkB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;CAChE;AAiBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,iBAAiB,CAAuB;IAChD,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,eAAe,CAAiE;IAExF,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAkB;gBAE5B,IAAI,EAAE,eAAe;IAQjC;;;;;;;;;;;;OAYG;IACH,kBAAkB,CAAC,EAAE,EAAE,gBAAgB,GAAG,IAAI;IAgC9C;;;;;;;;OAQG;IACH,mBAAmB,CAAC,EAAE,EAAE,gBAAgB,GAAG,IAAI;IAI/C;;;;;;;;;;;;;;;;OAgBG;IACH,gBAAgB,CAAC,CAAC,EAAE,gBAAgB,GAAG,iBAAiB,GAAG,IAAI;IAgD/D;;;;;;;;;;;;;;OAcG;IACH,WAAW,IAAI,OAAO;IAItB;;;;;;;;;;;;;;OAcG;IACH,mBAAmB,IAAI,MAAM,GAAG,IAAI;IAIpC;;;;;;;;;;;;;OAaG;IACH,QAAQ,IAAI,gBAAgB;IAa5B;;;;;;;;;;OAUG;IACH,KAAK,IAAI,IAAI;IAQb,qDAAqD;IACrD,OAAO,CAAC,cAAc;CAMvB"}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IME composition state machine for the RTIF web editor.
|
|
3
|
+
*
|
|
4
|
+
* During composition (CJK input, accent dead keys, dictation, emoji picker),
|
|
5
|
+
* the browser owns the DOM in the composing block. RTIF operations are NOT
|
|
6
|
+
* dispatched and the composing block is NOT reconciled until the composition
|
|
7
|
+
* session ends. On commit, a single {@link CompositionCommit} is returned
|
|
8
|
+
* so the caller can dispatch the appropriate RTIF operations.
|
|
9
|
+
*
|
|
10
|
+
* State machine:
|
|
11
|
+
* ```
|
|
12
|
+
* IDLE --compositionstart--> COMPOSING --compositionend--> IDLE
|
|
13
|
+
* | |
|
|
14
|
+
* (browser renders preview) (commit RTIF ops)
|
|
15
|
+
* (no RTIF ops dispatched)
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* @module
|
|
19
|
+
*/
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// Idle state singleton (avoids re-creating the same object)
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
const IDLE_STATE = {
|
|
24
|
+
composing: false,
|
|
25
|
+
composingBlockId: null,
|
|
26
|
+
startOffset: null,
|
|
27
|
+
selectionRange: null,
|
|
28
|
+
};
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
// CompositionHandler
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
/**
|
|
33
|
+
* Manages IME composition state for the RTIF web editor.
|
|
34
|
+
*
|
|
35
|
+
* Attach the three `onComposition*` methods to the corresponding DOM events
|
|
36
|
+
* on the contenteditable element. The handler tracks whether a composition
|
|
37
|
+
* session is active and produces a {@link CompositionCommit} when the session
|
|
38
|
+
* ends with committed text.
|
|
39
|
+
*
|
|
40
|
+
* During `isComposing() === true`:
|
|
41
|
+
* - The InputBridge must NOT dispatch RTIF operations for composition-related
|
|
42
|
+
* `beforeinput` events (`insertCompositionText`, `deleteByComposition`).
|
|
43
|
+
* - The InputBridge must NOT call `preventDefault()` on those events.
|
|
44
|
+
* - The Renderer must NOT reconcile the composing block.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* const handler = new CompositionHandler({
|
|
49
|
+
* getSelection: () => engine.state.selection,
|
|
50
|
+
* getBlockIdAtOffset: (offset) => {
|
|
51
|
+
* const { blockIndex } = resolve(engine.state.doc, offset);
|
|
52
|
+
* return engine.state.doc.blocks[blockIndex]?.id ?? null;
|
|
53
|
+
* },
|
|
54
|
+
* });
|
|
55
|
+
*
|
|
56
|
+
* el.addEventListener('compositionstart', (e) => handler.onCompositionStart(e));
|
|
57
|
+
* el.addEventListener('compositionupdate', (e) => handler.onCompositionUpdate(e));
|
|
58
|
+
* el.addEventListener('compositionend', (e) => {
|
|
59
|
+
* const commit = handler.onCompositionEnd(e);
|
|
60
|
+
* if (commit) {
|
|
61
|
+
* // dispatch RTIF operations from commit
|
|
62
|
+
* }
|
|
63
|
+
* });
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export class CompositionHandler {
|
|
67
|
+
_composing = false;
|
|
68
|
+
_composingBlockId = null;
|
|
69
|
+
_startOffset = null;
|
|
70
|
+
_selectionRange = null;
|
|
71
|
+
_deps;
|
|
72
|
+
constructor(deps) {
|
|
73
|
+
this._deps = deps;
|
|
74
|
+
}
|
|
75
|
+
// -----------------------------------------------------------------------
|
|
76
|
+
// Event handlers
|
|
77
|
+
// -----------------------------------------------------------------------
|
|
78
|
+
/**
|
|
79
|
+
* Handle the `compositionstart` DOM event.
|
|
80
|
+
*
|
|
81
|
+
* Enters the composing state. Reads the current RTIF selection to
|
|
82
|
+
* determine where the composition will insert text. If a non-collapsed
|
|
83
|
+
* selection exists, records it so the range can be deleted on commit
|
|
84
|
+
* (not on start, to avoid breaking IME).
|
|
85
|
+
*
|
|
86
|
+
* Does NOT call `preventDefault()` — the browser must be allowed to
|
|
87
|
+
* render its native composition preview.
|
|
88
|
+
*
|
|
89
|
+
* @param _e - The compositionstart event (data not used)
|
|
90
|
+
*/
|
|
91
|
+
onCompositionStart(_e) {
|
|
92
|
+
this._composing = true;
|
|
93
|
+
const selection = this._deps.getSelection();
|
|
94
|
+
if (selection === null) {
|
|
95
|
+
// No selection available — store nulls, compositionEnd will return null
|
|
96
|
+
this._composingBlockId = null;
|
|
97
|
+
this._startOffset = null;
|
|
98
|
+
this._selectionRange = null;
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const anchorOffset = selection.anchor.offset;
|
|
102
|
+
const focusOffset = selection.focus.offset;
|
|
103
|
+
// startOffset is always the focus position (where composition occurs)
|
|
104
|
+
this._startOffset = focusOffset;
|
|
105
|
+
// Resolve composing block from the focus offset
|
|
106
|
+
this._composingBlockId = this._deps.getBlockIdAtOffset(focusOffset);
|
|
107
|
+
// Record selection range if non-collapsed
|
|
108
|
+
if (anchorOffset !== focusOffset) {
|
|
109
|
+
const start = Math.min(anchorOffset, focusOffset);
|
|
110
|
+
const end = Math.max(anchorOffset, focusOffset);
|
|
111
|
+
this._selectionRange = { start, end };
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
this._selectionRange = null;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Handle the `compositionupdate` DOM event.
|
|
119
|
+
*
|
|
120
|
+
* This is intentionally a no-op. The browser is rendering its native
|
|
121
|
+
* composition preview and we must not interfere. No RTIF operations
|
|
122
|
+
* are dispatched during composition.
|
|
123
|
+
*
|
|
124
|
+
* @param _e - The compositionupdate event (ignored)
|
|
125
|
+
*/
|
|
126
|
+
onCompositionUpdate(_e) {
|
|
127
|
+
// Intentional no-op. Browser renders the composition preview.
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Handle the `compositionend` DOM event.
|
|
131
|
+
*
|
|
132
|
+
* Exits the composing state and returns a {@link CompositionCommit}
|
|
133
|
+
* describing the text to insert and any selection range to delete.
|
|
134
|
+
*
|
|
135
|
+
* Returns `null` if:
|
|
136
|
+
* - The committed text (`e.data`) is empty or null (composition cancelled)
|
|
137
|
+
* - No composition was in progress (`compositionstart` was never received)
|
|
138
|
+
* - The start offset is unknown (selection was null at composition start)
|
|
139
|
+
*
|
|
140
|
+
* The caller is responsible for dispatching RTIF operations from the
|
|
141
|
+
* returned commit.
|
|
142
|
+
*
|
|
143
|
+
* @param e - The compositionend event containing the committed text
|
|
144
|
+
* @returns A commit descriptor, or `null` if no operation should be dispatched
|
|
145
|
+
*/
|
|
146
|
+
onCompositionEnd(e) {
|
|
147
|
+
// If we weren't composing, nothing to commit
|
|
148
|
+
const wasComposing = this._composing;
|
|
149
|
+
const startOffset = this._startOffset;
|
|
150
|
+
const selectionRange = this._selectionRange;
|
|
151
|
+
// Always reset state, even if we return null
|
|
152
|
+
this._resetInternal();
|
|
153
|
+
if (!wasComposing) {
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
// If startOffset is null, we can't produce a valid commit
|
|
157
|
+
if (startOffset === null) {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
// Check for cancelled composition (empty or null data)
|
|
161
|
+
const committedText = e.data;
|
|
162
|
+
if (!committedText) {
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
// Build the commit
|
|
166
|
+
let deleteRange = null;
|
|
167
|
+
let insertOffset = startOffset;
|
|
168
|
+
if (selectionRange !== null) {
|
|
169
|
+
deleteRange = {
|
|
170
|
+
offset: selectionRange.start,
|
|
171
|
+
count: selectionRange.end - selectionRange.start,
|
|
172
|
+
};
|
|
173
|
+
// Insertion happens at the start of the deleted range
|
|
174
|
+
insertOffset = selectionRange.start;
|
|
175
|
+
}
|
|
176
|
+
return {
|
|
177
|
+
text: committedText,
|
|
178
|
+
offset: insertOffset,
|
|
179
|
+
deleteRange,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
// -----------------------------------------------------------------------
|
|
183
|
+
// State queries
|
|
184
|
+
// -----------------------------------------------------------------------
|
|
185
|
+
/**
|
|
186
|
+
* Whether a composition session is currently active.
|
|
187
|
+
*
|
|
188
|
+
* When `true`, the InputBridge and Renderer must defer to the browser's
|
|
189
|
+
* native composition handling.
|
|
190
|
+
*
|
|
191
|
+
* @returns `true` if between `compositionstart` and `compositionend`
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* ```ts
|
|
195
|
+
* if (compositionHandler.isComposing()) {
|
|
196
|
+
* // Skip RTIF operation dispatch and DOM reconciliation
|
|
197
|
+
* }
|
|
198
|
+
* ```
|
|
199
|
+
*/
|
|
200
|
+
isComposing() {
|
|
201
|
+
return this._composing;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* The block ID where the current composition is occurring.
|
|
205
|
+
*
|
|
206
|
+
* Used by the Renderer to skip reconciliation of this block during
|
|
207
|
+
* composition. Returns `null` when not composing or when the block
|
|
208
|
+
* could not be resolved.
|
|
209
|
+
*
|
|
210
|
+
* @returns The composing block ID, or `null`
|
|
211
|
+
*
|
|
212
|
+
* @example
|
|
213
|
+
* ```ts
|
|
214
|
+
* const blockId = compositionHandler.getComposingBlockId();
|
|
215
|
+
* reconcile(root, prevDoc, nextDoc, blockId);
|
|
216
|
+
* ```
|
|
217
|
+
*/
|
|
218
|
+
getComposingBlockId() {
|
|
219
|
+
return this._composingBlockId;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Return a snapshot of the current composition state.
|
|
223
|
+
*
|
|
224
|
+
* The returned object is a plain value — it will not change when the
|
|
225
|
+
* handler's internal state changes.
|
|
226
|
+
*
|
|
227
|
+
* @returns An immutable snapshot of the composition state
|
|
228
|
+
*
|
|
229
|
+
* @example
|
|
230
|
+
* ```ts
|
|
231
|
+
* const state = compositionHandler.getState();
|
|
232
|
+
* console.log(state.composing, state.composingBlockId);
|
|
233
|
+
* ```
|
|
234
|
+
*/
|
|
235
|
+
getState() {
|
|
236
|
+
if (!this._composing) {
|
|
237
|
+
return IDLE_STATE;
|
|
238
|
+
}
|
|
239
|
+
return {
|
|
240
|
+
composing: this._composing,
|
|
241
|
+
composingBlockId: this._composingBlockId,
|
|
242
|
+
startOffset: this._startOffset,
|
|
243
|
+
selectionRange: this._selectionRange,
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Force-reset the handler to idle state.
|
|
248
|
+
*
|
|
249
|
+
* Use this when the editor blurs, is destroyed, or needs to abandon
|
|
250
|
+
* a composition session for any reason.
|
|
251
|
+
*
|
|
252
|
+
* @example
|
|
253
|
+
* ```ts
|
|
254
|
+
* el.addEventListener('blur', () => compositionHandler.reset());
|
|
255
|
+
* ```
|
|
256
|
+
*/
|
|
257
|
+
reset() {
|
|
258
|
+
this._resetInternal();
|
|
259
|
+
}
|
|
260
|
+
// -----------------------------------------------------------------------
|
|
261
|
+
// Private
|
|
262
|
+
// -----------------------------------------------------------------------
|
|
263
|
+
/** Clear all internal state to the idle defaults. */
|
|
264
|
+
_resetInternal() {
|
|
265
|
+
this._composing = false;
|
|
266
|
+
this._composingBlockId = null;
|
|
267
|
+
this._startOffset = null;
|
|
268
|
+
this._selectionRange = null;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
//# sourceMappingURL=composition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"composition.js","sourceRoot":"","sources":["../src/composition.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content extraction — converts browser clipboard and drag events into
|
|
3
|
+
* {@link ContentItem} arrays for the content pipeline.
|
|
4
|
+
*
|
|
5
|
+
* This module bridges between the browser's DataTransfer API and the
|
|
6
|
+
* content pipeline's abstract ContentItem interface. It handles deduplication,
|
|
7
|
+
* lazy data access, and file wrapping.
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
import type { ContentItem, ContentItemSource } from './content-pipeline.js';
|
|
12
|
+
/**
|
|
13
|
+
* Extract content items from a ClipboardEvent.
|
|
14
|
+
*
|
|
15
|
+
* Uses the `DataTransferItemList` API when available for lazy data access.
|
|
16
|
+
* Falls back to `getData()` for string types. Deduplicates entries where both
|
|
17
|
+
* APIs provide the same MIME type.
|
|
18
|
+
*
|
|
19
|
+
* @param e - The clipboard event (from a 'paste' handler)
|
|
20
|
+
* @returns Array of ContentItem objects for pipeline processing
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* root.addEventListener('paste', (e) => {
|
|
25
|
+
* e.preventDefault();
|
|
26
|
+
* const items = extractFromPaste(e);
|
|
27
|
+
* pipeline.process(items, contextOpts);
|
|
28
|
+
* });
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export declare function extractFromPaste(e: ClipboardEvent): ContentItem[];
|
|
32
|
+
/**
|
|
33
|
+
* Extract content items from a DragEvent.
|
|
34
|
+
*
|
|
35
|
+
* Uses the `DataTransferItemList` API when available, falling back to
|
|
36
|
+
* `DataTransfer.files` and `getData()`. Items are created with source 'drop'.
|
|
37
|
+
*
|
|
38
|
+
* @param e - The drag event (from a 'drop' handler)
|
|
39
|
+
* @returns Array of ContentItem objects for pipeline processing
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* root.addEventListener('drop', (e) => {
|
|
44
|
+
* e.preventDefault();
|
|
45
|
+
* const items = extractFromDrop(e);
|
|
46
|
+
* pipeline.process(items, contextOpts);
|
|
47
|
+
* });
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export declare function extractFromDrop(e: DragEvent): ContentItem[];
|
|
51
|
+
/**
|
|
52
|
+
* Create a ContentItem from a File object.
|
|
53
|
+
*
|
|
54
|
+
* The `getString()` method returns `file.text()` for text MIME types,
|
|
55
|
+
* null otherwise. `getFile()` and `getBlob()` always return the file.
|
|
56
|
+
*
|
|
57
|
+
* @param file - The File to wrap
|
|
58
|
+
* @param source - How the file entered the editor
|
|
59
|
+
* @returns A ContentItem wrapping the file
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```ts
|
|
63
|
+
* const fileInput = document.querySelector('input[type=file]');
|
|
64
|
+
* const file = fileInput.files[0];
|
|
65
|
+
* const item = fileToContentItem(file, 'input');
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export declare function fileToContentItem(file: File, source: ContentItemSource): ContentItem;
|
|
69
|
+
//# sourceMappingURL=content-extraction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-extraction.d.ts","sourceRoot":"","sources":["../src/content-extraction.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAM5E;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,cAAc,GAAG,WAAW,EAAE,CAKjE;AAMD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,SAAS,GAAG,WAAW,EAAE,CAK3D;AAMD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,IAAI,EACV,MAAM,EAAE,iBAAiB,GACxB,WAAW,CAiBb"}
|