@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,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mark renderer registry — maps mark types to DOM rendering functions.
|
|
3
|
+
*
|
|
4
|
+
* The renderer consults this registry when creating span elements to apply
|
|
5
|
+
* visual mark effects (CSS classes, inline styles, data attributes).
|
|
6
|
+
* Built-in renderers handle bold, italic, underline, strikethrough, code,
|
|
7
|
+
* and link. Plugins can register custom renderers for additional marks.
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Create a new mark renderer registry.
|
|
13
|
+
*
|
|
14
|
+
* @returns An empty registry ready for renderer registration
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* const registry = createMarkRendererRegistry();
|
|
19
|
+
* registry.register('bold', boldRenderer);
|
|
20
|
+
* registry.register('italic', italicRenderer);
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export function createMarkRendererRegistry() {
|
|
24
|
+
const renderers = new Map();
|
|
25
|
+
const replacers = new Map();
|
|
26
|
+
return {
|
|
27
|
+
register(markType, renderer) {
|
|
28
|
+
renderers.set(markType, renderer);
|
|
29
|
+
},
|
|
30
|
+
get(markType) {
|
|
31
|
+
return renderers.get(markType);
|
|
32
|
+
},
|
|
33
|
+
isAtomic(markType) {
|
|
34
|
+
const renderer = renderers.get(markType);
|
|
35
|
+
return renderer?.atomic === true;
|
|
36
|
+
},
|
|
37
|
+
isExclusive(markType) {
|
|
38
|
+
const renderer = renderers.get(markType);
|
|
39
|
+
return renderer?.exclusive === true;
|
|
40
|
+
},
|
|
41
|
+
applyAll(el, marks) {
|
|
42
|
+
if (!marks)
|
|
43
|
+
return;
|
|
44
|
+
for (const [key, value] of Object.entries(marks)) {
|
|
45
|
+
if (value == null)
|
|
46
|
+
continue;
|
|
47
|
+
const renderer = renderers.get(key);
|
|
48
|
+
if (renderer) {
|
|
49
|
+
renderer.apply(el, value);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
registerReplacer(markType, replacer) {
|
|
54
|
+
replacers.set(markType, replacer);
|
|
55
|
+
},
|
|
56
|
+
getReplacer(markType) {
|
|
57
|
+
return replacers.get(markType);
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
// Built-in mark renderers
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
/**
|
|
65
|
+
* Built-in renderer for the `bold` mark.
|
|
66
|
+
* Adds the `rtif-bold` CSS class to the span element.
|
|
67
|
+
*/
|
|
68
|
+
export const boldRenderer = {
|
|
69
|
+
apply(el) {
|
|
70
|
+
el.classList.add('rtif-bold');
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* Built-in renderer for the `italic` mark.
|
|
75
|
+
* Adds the `rtif-italic` CSS class to the span element.
|
|
76
|
+
*/
|
|
77
|
+
export const italicRenderer = {
|
|
78
|
+
apply(el) {
|
|
79
|
+
el.classList.add('rtif-italic');
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Built-in renderer for the `underline` mark.
|
|
84
|
+
* Adds the `rtif-underline` CSS class to the span element.
|
|
85
|
+
*/
|
|
86
|
+
export const underlineRenderer = {
|
|
87
|
+
apply(el) {
|
|
88
|
+
el.classList.add('rtif-underline');
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* Built-in renderer for the `strikethrough` mark.
|
|
93
|
+
* Adds the `rtif-strikethrough` CSS class to the span element.
|
|
94
|
+
*/
|
|
95
|
+
export const strikethroughRenderer = {
|
|
96
|
+
apply(el) {
|
|
97
|
+
el.classList.add('rtif-strikethrough');
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* Built-in renderer for the `code` mark.
|
|
102
|
+
* Adds the `rtif-code` CSS class to the span element.
|
|
103
|
+
*/
|
|
104
|
+
export const codeRenderer = {
|
|
105
|
+
apply(el) {
|
|
106
|
+
el.classList.add('rtif-code');
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* Built-in renderer for the `link` mark.
|
|
111
|
+
* Adds the `rtif-link` CSS class and sets `data-link-href` attribute.
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```ts
|
|
115
|
+
* // Mark value: { href: "https://example.com", title: "Example" }
|
|
116
|
+
* // Result: <span class="rtif-link" data-link-href="https://example.com" title="Example">
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
export const linkRenderer = {
|
|
120
|
+
apply(el, value) {
|
|
121
|
+
el.classList.add('rtif-link');
|
|
122
|
+
if (typeof value === 'object' && value !== null) {
|
|
123
|
+
const linkData = value;
|
|
124
|
+
if (typeof linkData.href === 'string') {
|
|
125
|
+
el.setAttribute('data-link-href', linkData.href);
|
|
126
|
+
}
|
|
127
|
+
if (typeof linkData.title === 'string') {
|
|
128
|
+
el.setAttribute('title', linkData.title);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
exclusive: true,
|
|
133
|
+
};
|
|
134
|
+
/**
|
|
135
|
+
* Built-in renderer for the `color` mark.
|
|
136
|
+
* Sets the `color` CSS style on the span element.
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```ts
|
|
140
|
+
* // Mark value: "#ff0000"
|
|
141
|
+
* // Result: <span style="color: #ff0000;">
|
|
142
|
+
* ```
|
|
143
|
+
*/
|
|
144
|
+
export const colorRenderer = {
|
|
145
|
+
apply(el, value) {
|
|
146
|
+
if (typeof value === 'string') {
|
|
147
|
+
el.style.color = value;
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
/**
|
|
152
|
+
* Built-in renderer for the `fontSize` mark.
|
|
153
|
+
* Sets the `font-size` CSS style on the span element in pixels.
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* ```ts
|
|
157
|
+
* // Mark value: 16
|
|
158
|
+
* // Result: <span style="font-size: 16px;">
|
|
159
|
+
* ```
|
|
160
|
+
*/
|
|
161
|
+
export const fontSizeRenderer = {
|
|
162
|
+
apply(el, value) {
|
|
163
|
+
if (typeof value === 'number') {
|
|
164
|
+
el.style.fontSize = `${value}px`;
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
};
|
|
168
|
+
/**
|
|
169
|
+
* Built-in renderer for the `fontFamily` mark.
|
|
170
|
+
* Sets the `font-family` CSS style on the span element.
|
|
171
|
+
*
|
|
172
|
+
* @example
|
|
173
|
+
* ```ts
|
|
174
|
+
* // Mark value: "Georgia, serif"
|
|
175
|
+
* // Result: <span style="font-family: Georgia, serif;">
|
|
176
|
+
* ```
|
|
177
|
+
*/
|
|
178
|
+
export const fontFamilyRenderer = {
|
|
179
|
+
apply(el, value) {
|
|
180
|
+
if (typeof value === 'string') {
|
|
181
|
+
el.style.fontFamily = value;
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
};
|
|
185
|
+
/**
|
|
186
|
+
* Register all built-in mark renderers into a registry.
|
|
187
|
+
*
|
|
188
|
+
* Registers renderers for: bold, italic, underline, strikethrough, code,
|
|
189
|
+
* link, color, fontSize, fontFamily.
|
|
190
|
+
*
|
|
191
|
+
* @param registry - The registry to populate
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* ```ts
|
|
195
|
+
* const registry = createMarkRendererRegistry();
|
|
196
|
+
* registerBuiltinRenderers(registry);
|
|
197
|
+
* ```
|
|
198
|
+
*/
|
|
199
|
+
export function registerBuiltinRenderers(registry) {
|
|
200
|
+
registry.register('bold', boldRenderer);
|
|
201
|
+
registry.register('italic', italicRenderer);
|
|
202
|
+
registry.register('underline', underlineRenderer);
|
|
203
|
+
registry.register('strikethrough', strikethroughRenderer);
|
|
204
|
+
registry.register('code', codeRenderer);
|
|
205
|
+
registry.register('link', linkRenderer);
|
|
206
|
+
registry.register('color', colorRenderer);
|
|
207
|
+
registry.register('fontSize', fontSizeRenderer);
|
|
208
|
+
registry.register('fontFamily', fontFamilyRenderer);
|
|
209
|
+
}
|
|
210
|
+
//# sourceMappingURL=mark-renderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mark-renderer.js","sourceRoot":"","sources":["../src/mark-renderer.ts"],"names":[],"mappings":"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"}
|
package/dist/perf.d.ts
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Performance instrumentation for the RTIF web editor.
|
|
3
|
+
*
|
|
4
|
+
* Provides timing helpers built on the Performance API (`performance.mark()` /
|
|
5
|
+
* `performance.measure()`) to measure each phase of the editor operation cycle:
|
|
6
|
+
* dispatch, DOM reconciliation, and selection sync.
|
|
7
|
+
*
|
|
8
|
+
* When the Performance API is unavailable (e.g. SSR environments), all timing
|
|
9
|
+
* methods are no-ops and `collect()` returns zero-valued metrics.
|
|
10
|
+
*
|
|
11
|
+
* @packageDocumentation
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Timing metrics for a single editor operation cycle.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* const metrics = perf.collect();
|
|
19
|
+
* console.log(`Total: ${metrics.totalMs}ms`);
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export interface PerfMetrics {
|
|
23
|
+
/** Time spent in the engine dispatch (beforeApply + apply + afterApply) */
|
|
24
|
+
readonly dispatchMs: number;
|
|
25
|
+
/** Time spent reconciling the DOM to match the new document state */
|
|
26
|
+
readonly reconcileMs: number;
|
|
27
|
+
/** Time spent restoring the DOM selection after reconciliation */
|
|
28
|
+
readonly selectionSyncMs: number;
|
|
29
|
+
/** Wall-clock time from dispatch start to the last completed phase */
|
|
30
|
+
readonly totalMs: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Observer that receives timing data after each editor operation cycle.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* const observer: PerfObserver = {
|
|
38
|
+
* onMeasure(metrics) {
|
|
39
|
+
* if (metrics.totalMs > 16) {
|
|
40
|
+
* console.warn('Slow frame:', metrics);
|
|
41
|
+
* }
|
|
42
|
+
* },
|
|
43
|
+
* };
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export interface PerfObserver {
|
|
47
|
+
/** Called after each `collect()` with the computed metrics */
|
|
48
|
+
onMeasure(metrics: PerfMetrics): void;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Instrumentation handle for timing editor operation phases.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* const perf = createPerfInstrumentation();
|
|
56
|
+
* perf.markDispatchStart();
|
|
57
|
+
* engine.dispatch(ops);
|
|
58
|
+
* perf.markDispatchEnd();
|
|
59
|
+
* perf.markReconcileStart();
|
|
60
|
+
* reconcile(root, prev, next);
|
|
61
|
+
* perf.markReconcileEnd();
|
|
62
|
+
* perf.markSelectionSyncStart();
|
|
63
|
+
* setDomSelection(root, doc, sel);
|
|
64
|
+
* perf.markSelectionSyncEnd();
|
|
65
|
+
* const metrics = perf.collect();
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export interface PerfInstrumentation {
|
|
69
|
+
/** Mark the start of the engine dispatch phase */
|
|
70
|
+
markDispatchStart(): void;
|
|
71
|
+
/** Mark the end of the engine dispatch phase */
|
|
72
|
+
markDispatchEnd(): void;
|
|
73
|
+
/** Mark the start of DOM reconciliation */
|
|
74
|
+
markReconcileStart(): void;
|
|
75
|
+
/** Mark the end of DOM reconciliation */
|
|
76
|
+
markReconcileEnd(): void;
|
|
77
|
+
/** Mark the start of selection synchronization */
|
|
78
|
+
markSelectionSyncStart(): void;
|
|
79
|
+
/** Mark the end of selection synchronization */
|
|
80
|
+
markSelectionSyncEnd(): void;
|
|
81
|
+
/**
|
|
82
|
+
* Collect all marks, compute metrics, call observer (if set), and clean up.
|
|
83
|
+
*
|
|
84
|
+
* @returns The computed timing metrics for this cycle
|
|
85
|
+
*/
|
|
86
|
+
collect(): PerfMetrics;
|
|
87
|
+
/**
|
|
88
|
+
* Set or clear the observer that receives metrics after each `collect()`.
|
|
89
|
+
*
|
|
90
|
+
* @param observer - The observer, or `null` to remove
|
|
91
|
+
*/
|
|
92
|
+
setObserver(observer: PerfObserver | null): void;
|
|
93
|
+
/** Destroy the instrumentation and prevent further timing */
|
|
94
|
+
destroy(): void;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Create a performance instrumentation instance for timing editor operation
|
|
98
|
+
* phases.
|
|
99
|
+
*
|
|
100
|
+
* Uses `performance.mark()` / `performance.measure()` internally. When the
|
|
101
|
+
* Performance API is not available (SSR, Web Workers without it), all methods
|
|
102
|
+
* are safe no-ops and `collect()` returns zero-valued metrics.
|
|
103
|
+
*
|
|
104
|
+
* Each instrumentation instance maintains an internal counter so mark names
|
|
105
|
+
* never collide across cycles or across multiple instances.
|
|
106
|
+
*
|
|
107
|
+
* @returns A new {@link PerfInstrumentation} instance
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```ts
|
|
111
|
+
* const perf = createPerfInstrumentation();
|
|
112
|
+
* perf.setObserver({
|
|
113
|
+
* onMeasure(m) { console.log('dispatch', m.dispatchMs, 'ms'); },
|
|
114
|
+
* });
|
|
115
|
+
* perf.markDispatchStart();
|
|
116
|
+
* // ... engine dispatch ...
|
|
117
|
+
* perf.markDispatchEnd();
|
|
118
|
+
* const metrics = perf.collect();
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
121
|
+
export declare function createPerfInstrumentation(): PerfInstrumentation;
|
|
122
|
+
/**
|
|
123
|
+
* Wrap a synchronous function call with `performance.mark()` timing.
|
|
124
|
+
*
|
|
125
|
+
* Places `rtif:<label>:start` and `rtif:<label>:end` marks around the
|
|
126
|
+
* function execution, and measures the duration. If `perf` is `undefined`,
|
|
127
|
+
* the function is called without any instrumentation overhead.
|
|
128
|
+
*
|
|
129
|
+
* The function's return value is passed through unchanged. If the function
|
|
130
|
+
* throws, the end mark is still placed before the error propagates.
|
|
131
|
+
*
|
|
132
|
+
* @param label - A short descriptive label for the timing (e.g. `"reconcile"`)
|
|
133
|
+
* @param fn - The function to time
|
|
134
|
+
* @param perf - Optional instrumentation instance; if omitted, no timing occurs
|
|
135
|
+
* @returns The return value of `fn()`
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* ```ts
|
|
139
|
+
* const doc = withPerfTiming('reconcile', () => {
|
|
140
|
+
* return reconcile(root, prev, next);
|
|
141
|
+
* }, perf);
|
|
142
|
+
* ```
|
|
143
|
+
*/
|
|
144
|
+
export declare function withPerfTiming<T>(label: string, fn: () => T, perf?: PerfInstrumentation): T;
|
|
145
|
+
//# sourceMappingURL=perf.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"perf.d.ts","sourceRoot":"","sources":["../src/perf.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH;;;;;;;;GAQG;AACH,MAAM,WAAW,WAAW;IAC1B,2EAA2E;IAC3E,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,qEAAqE;IACrE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,kEAAkE;IAClE,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,sEAAsE;IACtE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,YAAY;IAC3B,8DAA8D;IAC9D,SAAS,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;CACvC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,mBAAmB;IAClC,kDAAkD;IAClD,iBAAiB,IAAI,IAAI,CAAC;IAC1B,gDAAgD;IAChD,eAAe,IAAI,IAAI,CAAC;IACxB,2CAA2C;IAC3C,kBAAkB,IAAI,IAAI,CAAC;IAC3B,yCAAyC;IACzC,gBAAgB,IAAI,IAAI,CAAC;IACzB,kDAAkD;IAClD,sBAAsB,IAAI,IAAI,CAAC;IAC/B,gDAAgD;IAChD,oBAAoB,IAAI,IAAI,CAAC;IAC7B;;;;OAIG;IACH,OAAO,IAAI,WAAW,CAAC;IACvB;;;;OAIG;IACH,WAAW,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI,GAAG,IAAI,CAAC;IACjD,6DAA6D;IAC7D,OAAO,IAAI,IAAI,CAAC;CACjB;AAmDD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,yBAAyB,IAAI,mBAAmB,CA+J/D;AAMD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAC9B,KAAK,EAAE,MAAM,EACb,EAAE,EAAE,MAAM,CAAC,EACX,IAAI,CAAC,EAAE,mBAAmB,GACzB,CAAC,CAwBH"}
|
package/dist/perf.js
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Performance instrumentation for the RTIF web editor.
|
|
3
|
+
*
|
|
4
|
+
* Provides timing helpers built on the Performance API (`performance.mark()` /
|
|
5
|
+
* `performance.measure()`) to measure each phase of the editor operation cycle:
|
|
6
|
+
* dispatch, DOM reconciliation, and selection sync.
|
|
7
|
+
*
|
|
8
|
+
* When the Performance API is unavailable (e.g. SSR environments), all timing
|
|
9
|
+
* methods are no-ops and `collect()` returns zero-valued metrics.
|
|
10
|
+
*
|
|
11
|
+
* @packageDocumentation
|
|
12
|
+
*/
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Constants
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
const ZERO_METRICS = Object.freeze({
|
|
17
|
+
dispatchMs: 0,
|
|
18
|
+
reconcileMs: 0,
|
|
19
|
+
selectionSyncMs: 0,
|
|
20
|
+
totalMs: 0,
|
|
21
|
+
});
|
|
22
|
+
const PREFIX = 'rtif:';
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
// Helpers
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
/**
|
|
27
|
+
* Check whether the `Performance` API is available in the current environment.
|
|
28
|
+
*/
|
|
29
|
+
function hasPerformanceApi() {
|
|
30
|
+
return (typeof performance !== 'undefined' &&
|
|
31
|
+
typeof performance.mark === 'function' &&
|
|
32
|
+
typeof performance.measure === 'function');
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Safely measure between two named marks, returning the duration in ms.
|
|
36
|
+
* Returns 0 if either mark is missing or the measure fails.
|
|
37
|
+
*/
|
|
38
|
+
function safeMeasure(measureName, startMark, endMark) {
|
|
39
|
+
try {
|
|
40
|
+
const entry = performance.measure(measureName, startMark, endMark);
|
|
41
|
+
return entry.duration;
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return 0;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
// Factory
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
/**
|
|
51
|
+
* Create a performance instrumentation instance for timing editor operation
|
|
52
|
+
* phases.
|
|
53
|
+
*
|
|
54
|
+
* Uses `performance.mark()` / `performance.measure()` internally. When the
|
|
55
|
+
* Performance API is not available (SSR, Web Workers without it), all methods
|
|
56
|
+
* are safe no-ops and `collect()` returns zero-valued metrics.
|
|
57
|
+
*
|
|
58
|
+
* Each instrumentation instance maintains an internal counter so mark names
|
|
59
|
+
* never collide across cycles or across multiple instances.
|
|
60
|
+
*
|
|
61
|
+
* @returns A new {@link PerfInstrumentation} instance
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```ts
|
|
65
|
+
* const perf = createPerfInstrumentation();
|
|
66
|
+
* perf.setObserver({
|
|
67
|
+
* onMeasure(m) { console.log('dispatch', m.dispatchMs, 'ms'); },
|
|
68
|
+
* });
|
|
69
|
+
* perf.markDispatchStart();
|
|
70
|
+
* // ... engine dispatch ...
|
|
71
|
+
* perf.markDispatchEnd();
|
|
72
|
+
* const metrics = perf.collect();
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
export function createPerfInstrumentation() {
|
|
76
|
+
const available = hasPerformanceApi();
|
|
77
|
+
let destroyed = false;
|
|
78
|
+
let observer = null;
|
|
79
|
+
let counter = 0;
|
|
80
|
+
// Current cycle's mark names (null when not yet placed)
|
|
81
|
+
let dispatchStartName = null;
|
|
82
|
+
let dispatchEndName = null;
|
|
83
|
+
let reconcileStartName = null;
|
|
84
|
+
let reconcileEndName = null;
|
|
85
|
+
let selectionSyncStartName = null;
|
|
86
|
+
let selectionSyncEndName = null;
|
|
87
|
+
// Track all mark names placed in the current cycle for cleanup
|
|
88
|
+
let currentCycleMarks = [];
|
|
89
|
+
function nextId() {
|
|
90
|
+
return counter++;
|
|
91
|
+
}
|
|
92
|
+
function placeMark(phase, edge) {
|
|
93
|
+
if (destroyed || !available)
|
|
94
|
+
return null;
|
|
95
|
+
const name = `${PREFIX}${phase}:${edge}:${nextId()}`;
|
|
96
|
+
performance.mark(name);
|
|
97
|
+
currentCycleMarks.push(name);
|
|
98
|
+
return name;
|
|
99
|
+
}
|
|
100
|
+
function cleanup(measureNames) {
|
|
101
|
+
if (!available)
|
|
102
|
+
return;
|
|
103
|
+
for (const name of currentCycleMarks) {
|
|
104
|
+
try {
|
|
105
|
+
performance.clearMarks(name);
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
// Ignore — mark may have already been cleaned up
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
for (const name of measureNames) {
|
|
112
|
+
try {
|
|
113
|
+
performance.clearMeasures(name);
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
// Ignore
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
currentCycleMarks = [];
|
|
120
|
+
}
|
|
121
|
+
function reset() {
|
|
122
|
+
dispatchStartName = null;
|
|
123
|
+
dispatchEndName = null;
|
|
124
|
+
reconcileStartName = null;
|
|
125
|
+
reconcileEndName = null;
|
|
126
|
+
selectionSyncStartName = null;
|
|
127
|
+
selectionSyncEndName = null;
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
markDispatchStart() {
|
|
131
|
+
dispatchStartName = placeMark('dispatch', 'start');
|
|
132
|
+
},
|
|
133
|
+
markDispatchEnd() {
|
|
134
|
+
dispatchEndName = placeMark('dispatch', 'end');
|
|
135
|
+
},
|
|
136
|
+
markReconcileStart() {
|
|
137
|
+
reconcileStartName = placeMark('reconcile', 'start');
|
|
138
|
+
},
|
|
139
|
+
markReconcileEnd() {
|
|
140
|
+
reconcileEndName = placeMark('reconcile', 'end');
|
|
141
|
+
},
|
|
142
|
+
markSelectionSyncStart() {
|
|
143
|
+
selectionSyncStartName = placeMark('selectionSync', 'start');
|
|
144
|
+
},
|
|
145
|
+
markSelectionSyncEnd() {
|
|
146
|
+
selectionSyncEndName = placeMark('selectionSync', 'end');
|
|
147
|
+
},
|
|
148
|
+
collect() {
|
|
149
|
+
if (destroyed || !available) {
|
|
150
|
+
const m = { ...ZERO_METRICS };
|
|
151
|
+
if (observer)
|
|
152
|
+
observer.onMeasure(m);
|
|
153
|
+
reset();
|
|
154
|
+
return m;
|
|
155
|
+
}
|
|
156
|
+
const measureNames = [];
|
|
157
|
+
const id = nextId();
|
|
158
|
+
// Measure each phase
|
|
159
|
+
let dispatchMs = 0;
|
|
160
|
+
if (dispatchStartName && dispatchEndName) {
|
|
161
|
+
const mn = `${PREFIX}dispatch:${id}`;
|
|
162
|
+
dispatchMs = safeMeasure(mn, dispatchStartName, dispatchEndName);
|
|
163
|
+
measureNames.push(mn);
|
|
164
|
+
}
|
|
165
|
+
let reconcileMs = 0;
|
|
166
|
+
if (reconcileStartName && reconcileEndName) {
|
|
167
|
+
const mn = `${PREFIX}reconcile:${id}`;
|
|
168
|
+
reconcileMs = safeMeasure(mn, reconcileStartName, reconcileEndName);
|
|
169
|
+
measureNames.push(mn);
|
|
170
|
+
}
|
|
171
|
+
let selectionSyncMs = 0;
|
|
172
|
+
if (selectionSyncStartName && selectionSyncEndName) {
|
|
173
|
+
const mn = `${PREFIX}selectionSync:${id}`;
|
|
174
|
+
selectionSyncMs = safeMeasure(mn, selectionSyncStartName, selectionSyncEndName);
|
|
175
|
+
measureNames.push(mn);
|
|
176
|
+
}
|
|
177
|
+
// Total: from dispatch start to the last available end mark
|
|
178
|
+
let totalMs = 0;
|
|
179
|
+
const totalStart = dispatchStartName;
|
|
180
|
+
const totalEnd = selectionSyncEndName ?? reconcileEndName ?? dispatchEndName;
|
|
181
|
+
if (totalStart && totalEnd) {
|
|
182
|
+
const mn = `${PREFIX}total:${id}`;
|
|
183
|
+
totalMs = safeMeasure(mn, totalStart, totalEnd);
|
|
184
|
+
measureNames.push(mn);
|
|
185
|
+
}
|
|
186
|
+
const metrics = {
|
|
187
|
+
dispatchMs,
|
|
188
|
+
reconcileMs,
|
|
189
|
+
selectionSyncMs,
|
|
190
|
+
totalMs,
|
|
191
|
+
};
|
|
192
|
+
// Clean up all marks and measures from this cycle
|
|
193
|
+
cleanup(measureNames);
|
|
194
|
+
reset();
|
|
195
|
+
if (observer) {
|
|
196
|
+
observer.onMeasure(metrics);
|
|
197
|
+
}
|
|
198
|
+
return metrics;
|
|
199
|
+
},
|
|
200
|
+
setObserver(obs) {
|
|
201
|
+
observer = obs;
|
|
202
|
+
},
|
|
203
|
+
destroy() {
|
|
204
|
+
destroyed = true;
|
|
205
|
+
reset();
|
|
206
|
+
currentCycleMarks = [];
|
|
207
|
+
},
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
// ---------------------------------------------------------------------------
|
|
211
|
+
// withPerfTiming utility
|
|
212
|
+
// ---------------------------------------------------------------------------
|
|
213
|
+
/**
|
|
214
|
+
* Wrap a synchronous function call with `performance.mark()` timing.
|
|
215
|
+
*
|
|
216
|
+
* Places `rtif:<label>:start` and `rtif:<label>:end` marks around the
|
|
217
|
+
* function execution, and measures the duration. If `perf` is `undefined`,
|
|
218
|
+
* the function is called without any instrumentation overhead.
|
|
219
|
+
*
|
|
220
|
+
* The function's return value is passed through unchanged. If the function
|
|
221
|
+
* throws, the end mark is still placed before the error propagates.
|
|
222
|
+
*
|
|
223
|
+
* @param label - A short descriptive label for the timing (e.g. `"reconcile"`)
|
|
224
|
+
* @param fn - The function to time
|
|
225
|
+
* @param perf - Optional instrumentation instance; if omitted, no timing occurs
|
|
226
|
+
* @returns The return value of `fn()`
|
|
227
|
+
*
|
|
228
|
+
* @example
|
|
229
|
+
* ```ts
|
|
230
|
+
* const doc = withPerfTiming('reconcile', () => {
|
|
231
|
+
* return reconcile(root, prev, next);
|
|
232
|
+
* }, perf);
|
|
233
|
+
* ```
|
|
234
|
+
*/
|
|
235
|
+
export function withPerfTiming(label, fn, perf) {
|
|
236
|
+
if (!perf || !hasPerformanceApi()) {
|
|
237
|
+
return fn();
|
|
238
|
+
}
|
|
239
|
+
const id = Date.now().toString(36) + Math.random().toString(36).slice(2, 6);
|
|
240
|
+
const startName = `${PREFIX}${label}:start:${id}`;
|
|
241
|
+
const endName = `${PREFIX}${label}:end:${id}`;
|
|
242
|
+
performance.mark(startName);
|
|
243
|
+
try {
|
|
244
|
+
return fn();
|
|
245
|
+
}
|
|
246
|
+
finally {
|
|
247
|
+
performance.mark(endName);
|
|
248
|
+
try {
|
|
249
|
+
const measureName = `${PREFIX}${label}:${id}`;
|
|
250
|
+
performance.measure(measureName, startName, endName);
|
|
251
|
+
performance.clearMarks(startName);
|
|
252
|
+
performance.clearMarks(endName);
|
|
253
|
+
performance.clearMeasures(measureName);
|
|
254
|
+
}
|
|
255
|
+
catch {
|
|
256
|
+
// Ignore measurement cleanup errors
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
//# sourceMappingURL=perf.js.map
|
package/dist/perf.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"perf.js","sourceRoot":"","sources":["../src/perf.ts"],"names":[],"mappings":"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"}
|