@effindomv2/runtime 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/LICENSE.md +6 -0
  2. package/dist/bridge.js +4 -0
  3. package/dist/bridge.js.map +7 -0
  4. package/dist/effindom.v2.manifest.json +68 -0
  5. package/dist/fonts/NotoColorEmoji.ttf +0 -0
  6. package/dist/fonts/NotoEmoji-Regular.ttf +0 -0
  7. package/dist/fonts/NotoSans-Bold.ttf +0 -0
  8. package/dist/fonts/NotoSans-BoldItalic.ttf +0 -0
  9. package/dist/fonts/NotoSans-Italic.ttf +0 -0
  10. package/dist/fonts/NotoSans-Regular.ttf +0 -0
  11. package/dist/fonts/NotoSansMono-Bold.ttf +0 -0
  12. package/dist/fonts/NotoSansMono-Regular.ttf +0 -0
  13. package/dist/fonts/NotoSansSymbols2-Regular.ttf +0 -0
  14. package/dist/harness.js +2 -0
  15. package/dist/harness.js.map +7 -0
  16. package/dist/index.html +53 -0
  17. package/dist/runtime/effindom-core-v2.wasm32-simd.JQXIaRaN0-JahfIVFiSLE49WzzCENvef_2EDEm09nJs.wasm +0 -0
  18. package/dist/runtime/effindom-core-v2.wasm32-simd.y7RzpkMARiFeRkpgiqKQsAfv4Hf17NYdpni-6aLNhMs.js.symbols +10079 -0
  19. package/dist/runtime/effindom-core-v2.wasm32-simd.yhT7DGUv4soEv4W91WVZl3T7T_ecKojk5_IcnwL79a0.js +1 -0
  20. package/dist/runtime/effindom-core-v2.wasm32.JSfMkp9ertJzSZxA-_xz3yacrJUhswxlwbqbJLRIuqw.wasm +0 -0
  21. package/dist/runtime/effindom-core-v2.wasm32.xNgsQv7dCwf8Uy-PfJSoRNyk9-q1OSogUwkk5g6ZBjk.js.symbols +10088 -0
  22. package/dist/runtime/effindom-core-v2.wasm32.yhT7DGUv4soEv4W91WVZl3T7T_ecKojk5_IcnwL79a0.js +1 -0
  23. package/dist/runtime/effindom-core-v2.wasm64-simd.GkByf-CPorNOs1CORny_8JjVk8Z3piiFq92r-uw1Syc.js +1 -0
  24. package/dist/runtime/effindom-core-v2.wasm64-simd.p4P98oRu2wEWxtRRW8RHr27JhGeWvWlziZXDM_z3Nc4.js.symbols +10286 -0
  25. package/dist/runtime/effindom-core-v2.wasm64-simd.y75FYXRwhQrpaDGYbZWrohGDv0AmjTb-EjXwOjBIgnM.wasm +0 -0
  26. package/dist/runtime/effindom-core-v2.wasm64.GkByf-CPorNOs1CORny_8JjVk8Z3piiFq92r-uw1Syc.js +1 -0
  27. package/dist/runtime/effindom-core-v2.wasm64.emhE1_CJs4_zXp8wiQS_5lYpUQ0OchmXgxksi0ykaBs.js.symbols +10298 -0
  28. package/dist/runtime/effindom-core-v2.wasm64.sO-Yu70cfN8Qs3a5iEp6cbFPaiOchqcMKUzryu4npNo.wasm +0 -0
  29. package/dist/runtime/effindom-ui-v2.wasm32-simd.0Mas1XD03eYvemryTioWaZOBuBA5ij7MFlTa8CgEZWs.wasm +0 -0
  30. package/dist/runtime/effindom-ui-v2.wasm32-simd.ThSDClMnSWdwf9d89JZfYor0G1Z6OxR4lOc75rNRuD4.js.symbols +1890 -0
  31. package/dist/runtime/effindom-ui-v2.wasm32-simd.wved0xEV4EKXVNBU3Sx7giD4faxD2YII9sQ2N_wCP4I.js +2 -0
  32. package/dist/runtime/effindom-ui-v2.wasm32.H7kYg99bT9ADGh0uUvj6H9Dk1L058nVFLv_4R79IXW8.js.symbols +1900 -0
  33. package/dist/runtime/effindom-ui-v2.wasm32.tp53X7nHfG_EUq29naDyElfnqhMw2D1Tr1T-BJAYO7w.wasm +0 -0
  34. package/dist/runtime/effindom-ui-v2.wasm32.wved0xEV4EKXVNBU3Sx7giD4faxD2YII9sQ2N_wCP4I.js +2 -0
  35. package/dist/runtime/effindom-ui-v2.wasm64-simd.86tk9Z3xIpgTOykET_8Nn9iUVJnp1AzOHW4fVQRGtQE.wasm +0 -0
  36. package/dist/runtime/effindom-ui-v2.wasm64-simd.RQaXil22Chu63-vxK9oOuX8wUY044kbo190oYIbBU4M.js.symbols +1918 -0
  37. package/dist/runtime/effindom-ui-v2.wasm64-simd.ZS1KEAg0XQex-VXkfgpBHE8MIoqPF8qpaf8nOjANb_U.js +2 -0
  38. package/dist/runtime/effindom-ui-v2.wasm64.YSwpMFbr-Q1SBe0Ze8mub1u1PqsvSz3QIYuA3eaUMME.js.symbols +1924 -0
  39. package/dist/runtime/effindom-ui-v2.wasm64.ZS1KEAg0XQex-VXkfgpBHE8MIoqPF8qpaf8nOjANb_U.js +2 -0
  40. package/dist/runtime/effindom-ui-v2.wasm64.ioQ9DuM6gR_EjlfRHdF8EvNPBcKCs0PQbbY9-cjTV6Y.wasm +0 -0
  41. package/dist/runtime/icudt_minimal.962CX1q0-Nbv-OqXPaub5piYTOLumUk-nEvemcvvnpw.dat +0 -0
  42. package/package.json +62 -0
  43. package/scripts/build.sh +279 -0
  44. package/scripts/build_assets.sh +51 -0
  45. package/scripts/font_assets.sh +52 -0
  46. package/scripts/generate_manifest.py +121 -0
  47. package/scripts/stage_package_assets.sh +42 -0
  48. package/src/bridge/commit-policy.ts +10 -0
  49. package/src/bridge/events/canvas-geometry.ts +78 -0
  50. package/src/bridge/events/key-router.ts +187 -0
  51. package/src/bridge/events/pointer-router.ts +619 -0
  52. package/src/bridge/events/semantic-hit-testing.ts +27 -0
  53. package/src/bridge/events.ts +54 -0
  54. package/src/bridge/find-dialog.ts +690 -0
  55. package/src/bridge/find-session.ts +158 -0
  56. package/src/bridge/font-catalog.ts +51 -0
  57. package/src/bridge/google-fonts.ts +63 -0
  58. package/src/bridge/incremental-font-packages.ts +216 -0
  59. package/src/bridge/init.ts +77 -0
  60. package/src/bridge/interaction/editor-model.ts +371 -0
  61. package/src/bridge/interaction/editor-mutations.ts +495 -0
  62. package/src/bridge/interaction/editor-session.ts +628 -0
  63. package/src/bridge/interaction/logs.ts +23 -0
  64. package/src/bridge/interaction/text-encoding.ts +51 -0
  65. package/src/bridge/interaction.ts +86 -0
  66. package/src/bridge/local-types.ts +105 -0
  67. package/src/bridge/platform.ts +68 -0
  68. package/src/bridge/pointer-move-coalescer.ts +41 -0
  69. package/src/bridge/pull-to-refresh.ts +124 -0
  70. package/src/bridge/render-loop.ts +268 -0
  71. package/src/bridge/runtime/asset-manager.ts +202 -0
  72. package/src/bridge/runtime/find-controller.ts +269 -0
  73. package/src/bridge/runtime/font-manager.ts +691 -0
  74. package/src/bridge/runtime/open-canvas-api.ts +72 -0
  75. package/src/bridge/runtime/semantic-controller.ts +133 -0
  76. package/src/bridge/runtime/text-documents.ts +234 -0
  77. package/src/bridge/runtime.ts +315 -0
  78. package/src/bridge/touch-gesture.ts +159 -0
  79. package/src/bridge/utils/assets.ts +572 -0
  80. package/src/bridge/utils/backends.ts +163 -0
  81. package/src/bridge/utils/encoding.ts +128 -0
  82. package/src/bridge/utils/fetch.ts +147 -0
  83. package/src/bridge/utils/heap.ts +118 -0
  84. package/src/bridge.ts +93 -0
  85. package/src/clipboard.ts +139 -0
  86. package/src/core-types.ts +595 -0
  87. package/src/find-on-page.ts +284 -0
  88. package/src/harness.ts +53 -0
  89. package/src/index.ts +40 -0
  90. package/src/open-canvas.ts +108 -0
  91. package/src/runtime-config.ts +96 -0
  92. package/src/semantic.ts +905 -0
@@ -0,0 +1,139 @@
1
+ import type { ClipboardRichTextPart, ClipboardRichTextPayload, ClipboardWritePayload } from './core-types';
2
+
3
+ export const EFFINDOM_RICH_TEXT_CLIPBOARD_MIME = 'web application/x-effindom-richtext+json';
4
+
5
+ function escapeHtml(text: string): string {
6
+ return text
7
+ .replace(/&/g, '&')
8
+ .replace(/</g, '&lt;')
9
+ .replace(/>/g, '&gt;')
10
+ .replace(/"/g, '&quot;')
11
+ .replace(/'/g, '&#39;');
12
+ }
13
+
14
+ function colorToCss(color: number): string {
15
+ const red = (color >>> 24) & 0xff;
16
+ const green = (color >>> 16) & 0xff;
17
+ const blue = (color >>> 8) & 0xff;
18
+ const alpha = color & 0xff;
19
+ if (alpha >= 0xff) {
20
+ return `rgb(${String(red)} ${String(green)} ${String(blue)})`;
21
+ }
22
+ return `rgb(${String(red)} ${String(green)} ${String(blue)} / ${(alpha / 255).toFixed(3)})`;
23
+ }
24
+
25
+ function inferClipboardCssFontFamily(fontUrl: string | undefined): string | null {
26
+ if (fontUrl === undefined) {
27
+ return null;
28
+ }
29
+ if (/mono/i.test(fontUrl)) {
30
+ return 'monospace';
31
+ }
32
+ return null;
33
+ }
34
+
35
+ function partStyleToCss(part: ClipboardRichTextPart): string {
36
+ const styles: string[] = [];
37
+ if (part.color !== undefined) {
38
+ styles.push(`color: ${colorToCss(part.color)};`);
39
+ }
40
+ if (part.bgColor !== undefined && part.bgColor !== 0) {
41
+ styles.push(`background-color: ${colorToCss(part.bgColor)};`);
42
+ }
43
+ if (part.fontSize !== undefined) {
44
+ styles.push(`font-size: ${String(part.fontSize)}px;`);
45
+ }
46
+ const fontFamily = inferClipboardCssFontFamily(part.fontUrl);
47
+ if (fontFamily !== null) {
48
+ styles.push(`font-family: ${fontFamily};`);
49
+ }
50
+ const decorationFlags = part.decorationFlags ?? 0;
51
+ const textDecorations: string[] = [];
52
+ if ((decorationFlags & 1) !== 0) {
53
+ textDecorations.push('underline');
54
+ }
55
+ if ((decorationFlags & 2) !== 0) {
56
+ textDecorations.push('line-through');
57
+ }
58
+ if (textDecorations.length > 0) {
59
+ styles.push(`text-decoration: ${textDecorations.join(' ')};`);
60
+ }
61
+ return styles.join(' ');
62
+ }
63
+
64
+ function buildClipboardHtml(richText: ClipboardRichTextPayload): string {
65
+ let html = '<div data-effindom-richtext="1" style="white-space: pre-wrap;">';
66
+ for (const part of richText.parts) {
67
+ const escapedText = escapeHtml(part.text);
68
+ const style = partStyleToCss(part);
69
+ if (style.length > 0) {
70
+ html += `<span style="${style}">${escapedText}</span>`;
71
+ continue;
72
+ }
73
+ html += escapedText;
74
+ }
75
+ html += '</div>';
76
+ return html;
77
+ }
78
+
79
+ export function enrichClipboardPayload(
80
+ payload: ClipboardWritePayload,
81
+ resolveFontUrl: (fontId: number) => string | null,
82
+ ): ClipboardWritePayload {
83
+ const richText = payload.richText;
84
+ if (richText === undefined) {
85
+ return payload;
86
+ }
87
+ return {
88
+ plainText: payload.plainText,
89
+ richText: {
90
+ version: richText.version,
91
+ parts: richText.parts.map((part) => {
92
+ if (part.fontId === undefined || part.fontUrl !== undefined) {
93
+ return part;
94
+ }
95
+ const fontUrl = resolveFontUrl(part.fontId);
96
+ return fontUrl === null ? part : { ...part, fontUrl };
97
+ }),
98
+ },
99
+ };
100
+ }
101
+
102
+ async function tryWriteClipboardItems(items: Record<string, Blob>): Promise<boolean> {
103
+ if (navigator.clipboard === undefined || navigator.clipboard.write === undefined || typeof ClipboardItem === 'undefined') {
104
+ return false;
105
+ }
106
+ try {
107
+ await navigator.clipboard.write([new ClipboardItem(items)]);
108
+ return true;
109
+ } catch {
110
+ return false;
111
+ }
112
+ }
113
+
114
+ export async function writeClipboardPayload(payload: ClipboardWritePayload): Promise<void> {
115
+ const plainText = payload.plainText;
116
+ const richText = payload.richText;
117
+ const html = richText === undefined ? null : buildClipboardHtml(richText);
118
+ if (richText !== undefined && html !== null) {
119
+ const richJson = JSON.stringify(richText);
120
+ const fullWriteSucceeded = await tryWriteClipboardItems({
121
+ 'text/plain': new Blob([plainText], { type: 'text/plain' }),
122
+ 'text/html': new Blob([html], { type: 'text/html' }),
123
+ [EFFINDOM_RICH_TEXT_CLIPBOARD_MIME]: new Blob([richJson], { type: EFFINDOM_RICH_TEXT_CLIPBOARD_MIME }),
124
+ });
125
+ if (fullWriteSucceeded) {
126
+ return;
127
+ }
128
+ const htmlWriteSucceeded = await tryWriteClipboardItems({
129
+ 'text/plain': new Blob([plainText], { type: 'text/plain' }),
130
+ 'text/html': new Blob([html], { type: 'text/html' }),
131
+ });
132
+ if (htmlWriteSucceeded) {
133
+ return;
134
+ }
135
+ }
136
+ if (navigator.clipboard !== undefined && navigator.clipboard.writeText !== undefined) {
137
+ await navigator.clipboard.writeText(plainText);
138
+ }
139
+ }