@stll/folio-core 0.4.0 → 0.6.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 (98) hide show
  1. package/dist/ai-edits/apply.d.ts +3 -9
  2. package/dist/ai-edits/apply.js +94 -14
  3. package/dist/ai-edits/blockRange.d.ts +33 -0
  4. package/dist/ai-edits/blockRange.js +58 -0
  5. package/dist/ai-edits/headless.d.ts +37 -4
  6. package/dist/ai-edits/headless.js +134 -16
  7. package/dist/ai-edits/index.d.ts +5 -3
  8. package/dist/ai-edits/index.js +3 -2
  9. package/dist/ai-edits/snapshot.d.ts +14 -2
  10. package/dist/ai-edits/snapshot.js +12 -1
  11. package/dist/ai-edits/types.d.ts +42 -3
  12. package/dist/compat/eigenpal.d.ts +3 -2
  13. package/dist/compat/eigenpal.js +6 -5
  14. package/dist/controller/layoutPipeline.d.ts +1 -0
  15. package/dist/controller/layoutPipeline.js +35 -137
  16. package/dist/controller/layoutScheduler.d.ts +2 -1
  17. package/dist/controller/layoutScheduler.js +6 -0
  18. package/dist/document-operations.d.ts +139 -0
  19. package/dist/document-operations.js +578 -0
  20. package/dist/docx/blockContentParser.js +17 -7
  21. package/dist/docx/encryption/agileDecryption.js +2 -1
  22. package/dist/docx/encryption/compoundFile.js +4 -2
  23. package/dist/docx/footnoteParser.d.ts +1 -17
  24. package/dist/docx/footnoteParser.js +1 -27
  25. package/dist/docx/groupDrawingParser.d.ts +8 -0
  26. package/dist/docx/groupDrawingParser.js +131 -0
  27. package/dist/docx/numberingParser.d.ts +3 -1
  28. package/dist/docx/numberingParser.js +8 -2
  29. package/dist/docx/paragraphParser.js +9 -3
  30. package/dist/docx/runParser.js +8 -1
  31. package/dist/docx/selectiveXmlPatch.js +4 -10
  32. package/dist/docx/serializer/numberingSerializer.js +3 -1
  33. package/dist/docx/settingsParser.d.ts +6 -3
  34. package/dist/docx/settingsParser.js +2 -0
  35. package/dist/docx/xmlParser.js +11 -4
  36. package/dist/i18n/messages/catalogs.gen.d.ts +1054 -34
  37. package/dist/i18n/messages/catalogs.gen.js +1122 -68
  38. package/dist/i18n/messages/messages.gen.d.ts +62 -2
  39. package/dist/index.d.ts +3 -2
  40. package/dist/index.js +6 -5
  41. package/dist/layout-bridge/convert/footnoteLayout.d.ts +37 -1
  42. package/dist/layout-bridge/convert/footnoteLayout.js +138 -14
  43. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +5 -7
  44. package/dist/layout-bridge/convert/headerFooterLayout.js +5 -7
  45. package/dist/layout-bridge/convert/toFlowBlocks.js +56 -19
  46. package/dist/layout-engine/index.d.ts +6 -5
  47. package/dist/layout-engine/index.js +143 -30
  48. package/dist/layout-engine/keep-together.d.ts +13 -8
  49. package/dist/layout-engine/keep-together.js +40 -25
  50. package/dist/layout-engine/layoutInstrumentation.d.ts +11 -1
  51. package/dist/layout-engine/layoutInstrumentation.js +10 -1
  52. package/dist/layout-engine/measure/measureBlocks.js +50 -18
  53. package/dist/layout-engine/measure/measureParagraph.js +61 -15
  54. package/dist/layout-engine/paginator.d.ts +2 -1
  55. package/dist/layout-engine/paginator.js +9 -3
  56. package/dist/layout-engine/textBoxGroup.d.ts +7 -0
  57. package/dist/layout-engine/textBoxGroup.js +8 -0
  58. package/dist/layout-engine/types.d.ts +30 -9
  59. package/dist/layout-engine/types.js +20 -2
  60. package/dist/layout-painter/renderPage.d.ts +15 -1
  61. package/dist/layout-painter/renderPage.js +27 -11
  62. package/dist/layout-painter/renderParagraph.js +18 -8
  63. package/dist/layout-painter/renderTable.js +10 -7
  64. package/dist/managers/DocumentLoaderManager.js +12 -5
  65. package/dist/model.js +1 -1
  66. package/dist/paged-layout/pageText.d.ts +14 -0
  67. package/dist/paged-layout/pageText.js +21 -0
  68. package/dist/prosemirror/attrs/index.js +2 -0
  69. package/dist/prosemirror/commands/comments.js +75 -5
  70. package/dist/prosemirror/commands/hyperlink.js +4 -2
  71. package/dist/prosemirror/commands/image.js +2 -1
  72. package/dist/prosemirror/commands/propertyChangeScope.d.ts +68 -0
  73. package/dist/prosemirror/commands/propertyChangeScope.js +242 -0
  74. package/dist/prosemirror/conversion/fromProseDoc.js +14 -3
  75. package/dist/prosemirror/conversion/toProseDoc.js +29 -8
  76. package/dist/prosemirror/extensions/core/ParagraphExtension.js +2 -0
  77. package/dist/prosemirror/extensions/features/ListExtension.js +6 -0
  78. package/dist/prosemirror/extensions/nodes/TableExtension.js +10 -11
  79. package/dist/prosemirror/findReplaceSelection.js +2 -1
  80. package/dist/prosemirror/schema/nodes.d.ts +10 -5
  81. package/dist/prosemirror/styles/resolvedStyleAttrs.js +1 -0
  82. package/dist/prosemirror/utils/tabCalculator.js +4 -2
  83. package/dist/redline.d.ts +20 -0
  84. package/dist/redline.js +127 -0
  85. package/dist/server.d.ts +7 -3
  86. package/dist/server.js +6 -2
  87. package/dist/symbols.d.ts +35 -0
  88. package/dist/symbols.js +512 -0
  89. package/dist/utils/clipboard.js +3 -3
  90. package/dist/utils/fontLoader.js +3 -0
  91. package/dist/utils/fontResolver.js +48 -1
  92. package/dist/utils/zoom.d.ts +21 -0
  93. package/dist/utils/zoom.js +21 -0
  94. package/dist/version-comparison.d.ts +92 -0
  95. package/dist/version-comparison.js +436 -0
  96. package/package.json +3 -3
  97. package/dist/paged-layout/headerFooterMargins.d.ts +0 -75
  98. package/dist/paged-layout/headerFooterMargins.js +0 -122
@@ -0,0 +1,512 @@
1
+ //#region src/symbols.ts
2
+ const SYMBOL_CATEGORIES = [
3
+ {
4
+ name: "Common",
5
+ nameKey: "dialogs.insertSymbol.categories.common",
6
+ symbols: [
7
+ {
8
+ char: "©",
9
+ name: "Copyright"
10
+ },
11
+ {
12
+ char: "®",
13
+ name: "Registered"
14
+ },
15
+ {
16
+ char: "™",
17
+ name: "Trademark"
18
+ },
19
+ {
20
+ char: "•",
21
+ name: "Bullet"
22
+ },
23
+ {
24
+ char: "…",
25
+ name: "Ellipsis"
26
+ },
27
+ {
28
+ char: "—",
29
+ name: "Em dash"
30
+ },
31
+ {
32
+ char: "–",
33
+ name: "En dash"
34
+ },
35
+ {
36
+ char: "±",
37
+ name: "Plus-minus"
38
+ },
39
+ {
40
+ char: "×",
41
+ name: "Multiply"
42
+ },
43
+ {
44
+ char: "÷",
45
+ name: "Divide"
46
+ },
47
+ {
48
+ char: "≠",
49
+ name: "Not equal"
50
+ },
51
+ {
52
+ char: "≈",
53
+ name: "Approximately"
54
+ },
55
+ {
56
+ char: "≤",
57
+ name: "Less or equal"
58
+ },
59
+ {
60
+ char: "≥",
61
+ name: "Greater or equal"
62
+ },
63
+ {
64
+ char: "°",
65
+ name: "Degree"
66
+ },
67
+ {
68
+ char: "µ",
69
+ name: "Micro"
70
+ },
71
+ {
72
+ char: "¶",
73
+ name: "Pilcrow"
74
+ },
75
+ {
76
+ char: "§",
77
+ name: "Section"
78
+ },
79
+ {
80
+ char: "†",
81
+ name: "Dagger"
82
+ },
83
+ {
84
+ char: "‡",
85
+ name: "Double dagger"
86
+ },
87
+ {
88
+ char: "¿",
89
+ name: "Inverted question"
90
+ },
91
+ {
92
+ char: "¡",
93
+ name: "Inverted exclamation"
94
+ },
95
+ {
96
+ char: "‰",
97
+ name: "Per mille"
98
+ },
99
+ {
100
+ char: "∞",
101
+ name: "Infinity"
102
+ }
103
+ ]
104
+ },
105
+ {
106
+ name: "Arrows",
107
+ nameKey: "dialogs.insertSymbol.categories.arrows",
108
+ symbols: [
109
+ {
110
+ char: "←",
111
+ name: "Left"
112
+ },
113
+ {
114
+ char: "→",
115
+ name: "Right"
116
+ },
117
+ {
118
+ char: "↑",
119
+ name: "Up"
120
+ },
121
+ {
122
+ char: "↓",
123
+ name: "Down"
124
+ },
125
+ {
126
+ char: "↔",
127
+ name: "Left-right"
128
+ },
129
+ {
130
+ char: "↕",
131
+ name: "Up-down"
132
+ },
133
+ {
134
+ char: "⇐",
135
+ name: "Double left"
136
+ },
137
+ {
138
+ char: "⇒",
139
+ name: "Double right"
140
+ },
141
+ {
142
+ char: "⇑",
143
+ name: "Double up"
144
+ },
145
+ {
146
+ char: "⇓",
147
+ name: "Double down"
148
+ },
149
+ {
150
+ char: "⇔",
151
+ name: "Double left-right"
152
+ },
153
+ {
154
+ char: "➡",
155
+ name: "Heavy right"
156
+ },
157
+ {
158
+ char: "↩",
159
+ name: "Return"
160
+ },
161
+ {
162
+ char: "↪",
163
+ name: "Curved right"
164
+ },
165
+ {
166
+ char: "↻",
167
+ name: "Clockwise"
168
+ },
169
+ {
170
+ char: "↺",
171
+ name: "Counter-clockwise"
172
+ }
173
+ ]
174
+ },
175
+ {
176
+ name: "Math",
177
+ nameKey: "dialogs.insertSymbol.categories.math",
178
+ symbols: [
179
+ {
180
+ char: "∑",
181
+ name: "Summation"
182
+ },
183
+ {
184
+ char: "∏",
185
+ name: "Product"
186
+ },
187
+ {
188
+ char: "∫",
189
+ name: "Integral"
190
+ },
191
+ {
192
+ char: "√",
193
+ name: "Square root"
194
+ },
195
+ {
196
+ char: "∂",
197
+ name: "Partial diff"
198
+ },
199
+ {
200
+ char: "∇",
201
+ name: "Nabla"
202
+ },
203
+ {
204
+ char: "∈",
205
+ name: "Element of"
206
+ },
207
+ {
208
+ char: "∉",
209
+ name: "Not element"
210
+ },
211
+ {
212
+ char: "⊂",
213
+ name: "Subset"
214
+ },
215
+ {
216
+ char: "⊃",
217
+ name: "Superset"
218
+ },
219
+ {
220
+ char: "∪",
221
+ name: "Union"
222
+ },
223
+ {
224
+ char: "∩",
225
+ name: "Intersection"
226
+ },
227
+ {
228
+ char: "∧",
229
+ name: "And"
230
+ },
231
+ {
232
+ char: "∨",
233
+ name: "Or"
234
+ },
235
+ {
236
+ char: "¬",
237
+ name: "Not"
238
+ },
239
+ {
240
+ char: "∀",
241
+ name: "For all"
242
+ },
243
+ {
244
+ char: "∃",
245
+ name: "Exists"
246
+ },
247
+ {
248
+ char: "∅",
249
+ name: "Empty set"
250
+ },
251
+ {
252
+ char: "∝",
253
+ name: "Proportional"
254
+ },
255
+ {
256
+ char: "∠",
257
+ name: "Angle"
258
+ }
259
+ ]
260
+ },
261
+ {
262
+ name: "Greek",
263
+ nameKey: "dialogs.insertSymbol.categories.greek",
264
+ symbols: [
265
+ {
266
+ char: "α",
267
+ name: "alpha"
268
+ },
269
+ {
270
+ char: "β",
271
+ name: "beta"
272
+ },
273
+ {
274
+ char: "γ",
275
+ name: "gamma"
276
+ },
277
+ {
278
+ char: "δ",
279
+ name: "delta"
280
+ },
281
+ {
282
+ char: "ε",
283
+ name: "epsilon"
284
+ },
285
+ {
286
+ char: "ζ",
287
+ name: "zeta"
288
+ },
289
+ {
290
+ char: "η",
291
+ name: "eta"
292
+ },
293
+ {
294
+ char: "θ",
295
+ name: "theta"
296
+ },
297
+ {
298
+ char: "λ",
299
+ name: "lambda"
300
+ },
301
+ {
302
+ char: "μ",
303
+ name: "mu"
304
+ },
305
+ {
306
+ char: "π",
307
+ name: "pi"
308
+ },
309
+ {
310
+ char: "ρ",
311
+ name: "rho"
312
+ },
313
+ {
314
+ char: "σ",
315
+ name: "sigma"
316
+ },
317
+ {
318
+ char: "τ",
319
+ name: "tau"
320
+ },
321
+ {
322
+ char: "φ",
323
+ name: "phi"
324
+ },
325
+ {
326
+ char: "ψ",
327
+ name: "psi"
328
+ },
329
+ {
330
+ char: "ω",
331
+ name: "omega"
332
+ },
333
+ {
334
+ char: "Δ",
335
+ name: "Delta"
336
+ },
337
+ {
338
+ char: "Σ",
339
+ name: "Sigma"
340
+ },
341
+ {
342
+ char: "Ω",
343
+ name: "Omega"
344
+ },
345
+ {
346
+ char: "Π",
347
+ name: "Pi"
348
+ },
349
+ {
350
+ char: "Φ",
351
+ name: "Phi"
352
+ },
353
+ {
354
+ char: "Ψ",
355
+ name: "Psi"
356
+ },
357
+ {
358
+ char: "Θ",
359
+ name: "Theta"
360
+ }
361
+ ]
362
+ },
363
+ {
364
+ name: "Currency",
365
+ nameKey: "dialogs.insertSymbol.categories.currency",
366
+ symbols: [
367
+ {
368
+ char: "$",
369
+ name: "Dollar"
370
+ },
371
+ {
372
+ char: "€",
373
+ name: "Euro"
374
+ },
375
+ {
376
+ char: "£",
377
+ name: "Pound"
378
+ },
379
+ {
380
+ char: "¥",
381
+ name: "Yen"
382
+ },
383
+ {
384
+ char: "₹",
385
+ name: "Rupee"
386
+ },
387
+ {
388
+ char: "₽",
389
+ name: "Ruble"
390
+ },
391
+ {
392
+ char: "₩",
393
+ name: "Won"
394
+ },
395
+ {
396
+ char: "₿",
397
+ name: "Bitcoin"
398
+ },
399
+ {
400
+ char: "¢",
401
+ name: "Cent"
402
+ },
403
+ {
404
+ char: "₫",
405
+ name: "Dong"
406
+ },
407
+ {
408
+ char: "₺",
409
+ name: "Lira"
410
+ },
411
+ {
412
+ char: "₴",
413
+ name: "Hryvnia"
414
+ }
415
+ ]
416
+ },
417
+ {
418
+ name: "Shapes",
419
+ nameKey: "dialogs.insertSymbol.categories.shapes",
420
+ symbols: [
421
+ {
422
+ char: "■",
423
+ name: "Black square"
424
+ },
425
+ {
426
+ char: "□",
427
+ name: "White square"
428
+ },
429
+ {
430
+ char: "▲",
431
+ name: "Up triangle"
432
+ },
433
+ {
434
+ char: "▼",
435
+ name: "Down triangle"
436
+ },
437
+ {
438
+ char: "●",
439
+ name: "Black circle"
440
+ },
441
+ {
442
+ char: "○",
443
+ name: "White circle"
444
+ },
445
+ {
446
+ char: "◆",
447
+ name: "Black diamond"
448
+ },
449
+ {
450
+ char: "◇",
451
+ name: "White diamond"
452
+ },
453
+ {
454
+ char: "★",
455
+ name: "Black star"
456
+ },
457
+ {
458
+ char: "☆",
459
+ name: "White star"
460
+ },
461
+ {
462
+ char: "♠",
463
+ name: "Spade"
464
+ },
465
+ {
466
+ char: "♥",
467
+ name: "Heart"
468
+ },
469
+ {
470
+ char: "♦",
471
+ name: "Diamond"
472
+ },
473
+ {
474
+ char: "♣",
475
+ name: "Club"
476
+ },
477
+ {
478
+ char: "✓",
479
+ name: "Check mark"
480
+ },
481
+ {
482
+ char: "✗",
483
+ name: "Ballot X"
484
+ },
485
+ {
486
+ char: "✦",
487
+ name: "Four pointed star"
488
+ },
489
+ {
490
+ char: "◌",
491
+ name: "Dotted circle"
492
+ }
493
+ ]
494
+ }
495
+ ];
496
+ /** Every catalog symbol, flattened and tagged with its category. */
497
+ const ALL_SYMBOLS = SYMBOL_CATEGORIES.flatMap((category) => category.symbols.map((symbol) => ({
498
+ ...symbol,
499
+ category: category.name
500
+ })));
501
+ /**
502
+ * Symbols whose descriptive name contains `query` (case-insensitive), or whose
503
+ * character is exactly `query`. An empty/whitespace query returns `[]` so
504
+ * callers fall back to the active category.
505
+ */
506
+ function filterSymbols(query) {
507
+ const q = query.trim().toLowerCase();
508
+ if (!q) return [];
509
+ return ALL_SYMBOLS.filter((symbol) => symbol.name.toLowerCase().includes(q) || symbol.char === q);
510
+ }
511
+ //#endregion
512
+ export { ALL_SYMBOLS, SYMBOL_CATEGORIES, filterSymbols };
@@ -86,7 +86,7 @@ async function copyRuns(runs, options = {}) {
86
86
  try {
87
87
  return await writeToClipboard(runsToClipboardContent(runs, includeFormatting));
88
88
  } catch (error) {
89
- onError?.(error);
89
+ onError?.(error instanceof Error ? error : new Error(String(error)));
90
90
  return false;
91
91
  }
92
92
  }
@@ -98,7 +98,7 @@ async function copyParagraphs(paragraphs, options = {}) {
98
98
  try {
99
99
  return await writeToClipboard(paragraphsToClipboardContent(paragraphs, includeFormatting));
100
100
  } catch (error) {
101
- onError?.(error);
101
+ onError?.(error instanceof Error ? error : new Error(String(error)));
102
102
  return false;
103
103
  }
104
104
  }
@@ -170,7 +170,7 @@ async function readFromClipboard(options = {}) {
170
170
  try {
171
171
  return await parseClipboardItems(await navigator.clipboard.read(), cleanWordFormatting);
172
172
  } catch (error) {
173
- onError?.(error);
173
+ onError?.(error instanceof Error ? error : new Error(String(error)));
174
174
  return null;
175
175
  }
176
176
  }
@@ -17,6 +17,8 @@ let isLoadingAny = false;
17
17
  * this map is used for font availability checks and preloading.
18
18
  */
19
19
  const FONT_MAPPING = {
20
+ Aptos: "Source Sans 3",
21
+ "Aptos Display": "Source Sans 3",
20
22
  Calibri: "Carlito",
21
23
  Cambria: "Caladea",
22
24
  Arial: "Arimo",
@@ -38,6 +40,7 @@ const BUNDLED_FONTS = /* @__PURE__ */ new Set([
38
40
  "Arimo",
39
41
  "Tinos",
40
42
  "Cousine",
43
+ "Source Sans 3",
41
44
  "Calibri",
42
45
  "Cambria",
43
46
  "Arial",
@@ -44,6 +44,11 @@ const JP_MEASURED_LINE_HEIGHT = {
44
44
  ratio: 1.303,
45
45
  note: "Measured against real Word: 10.5pt Japanese body, non-grid section, renders at 13.68pt line pitch."
46
46
  };
47
+ const APTOS_MEASURED_LINE_HEIGHT = {
48
+ source: "measured",
49
+ ratio: 1.2207,
50
+ note: "Measured against real Word: 11pt Aptos body, non-grid section, renders at 13.43pt line pitch."
51
+ };
47
52
  /**
48
53
  * Mapping of common DOCX fonts to Google Fonts equivalents
49
54
  *
@@ -59,6 +64,30 @@ const JP_MEASURED_LINE_HEIGHT = {
59
64
  * ratios carried over unchanged, pending measurement.
60
65
  */
61
66
  const FONT_MAPPINGS = {
67
+ aptos: {
68
+ googleFont: "Source Sans 3",
69
+ category: "sans-serif",
70
+ fallbackStack: [
71
+ "Aptos",
72
+ "Source Sans 3",
73
+ "Arial",
74
+ "Helvetica",
75
+ "sans-serif"
76
+ ],
77
+ singleLineRatio: singleLineRatioOf(APTOS_MEASURED_LINE_HEIGHT)
78
+ },
79
+ "aptos display": {
80
+ googleFont: "Source Sans 3",
81
+ category: "sans-serif",
82
+ fallbackStack: [
83
+ "Aptos Display",
84
+ "Source Sans 3",
85
+ "Arial",
86
+ "Helvetica",
87
+ "sans-serif"
88
+ ],
89
+ singleLineRatio: singleLineRatioOf(APTOS_MEASURED_LINE_HEIGHT)
90
+ },
62
91
  calibri: {
63
92
  googleFont: "Carlito",
64
93
  category: "sans-serif",
@@ -213,6 +242,23 @@ const FONT_MAPPINGS = {
213
242
  unitsPerEm: 2048
214
243
  })
215
244
  },
245
+ montserrat: {
246
+ googleFont: "Montserrat",
247
+ category: "sans-serif",
248
+ fallbackStack: [
249
+ "Montserrat",
250
+ "Arial",
251
+ "Helvetica",
252
+ "sans-serif"
253
+ ],
254
+ singleLineRatio: singleLineRatioOf({
255
+ source: "hhea",
256
+ hheaAscent: 968,
257
+ hheaDescent: -251,
258
+ hheaLineGap: 0,
259
+ unitsPerEm: 1e3
260
+ })
261
+ },
216
262
  "trebuchet ms": {
217
263
  googleFont: "Fira Sans",
218
264
  category: "sans-serif",
@@ -759,7 +805,8 @@ function resolveFontFamily(docxFontName) {
759
805
  singleLineRatio: mapping.singleLineRatio
760
806
  };
761
807
  }
762
- const defaultFallback = DEFAULT_FALLBACKS[detectFontCategory(docxFontName)];
808
+ const category = detectFontCategory(docxFontName);
809
+ const defaultFallback = DEFAULT_FALLBACKS[category];
763
810
  return {
764
811
  googleFont: null,
765
812
  cssFallback: withArabicFallback(`${quoteFontName(docxFontName)}, ${defaultFallback}`),
@@ -0,0 +1,21 @@
1
+ //#region src/utils/zoom.d.ts
2
+ /**
3
+ * Canonical zoom limits shared by every folio adapter (React, Vue, ...).
4
+ *
5
+ * Adapters must source their zoom range from here rather than hard-coding their
6
+ * own, so the reachable zoom span stays identical across framework hosts.
7
+ * Historically React clamped 0.25-4x while Vue clamped 0.5-2x; this module is
8
+ * the single source of truth that keeps them from drifting again.
9
+ *
10
+ * Note: the discrete zoom-level menu each adapter shows in its toolbar dropdown
11
+ * is a separate, deliberately curated subset (50-200%); it is not derived from
12
+ * these limits.
13
+ */
14
+ /** Minimum reachable zoom level (25%). */
15
+ declare const ZOOM_MIN = 0.25;
16
+ /** Maximum reachable zoom level (400%). */
17
+ declare const ZOOM_MAX = 4;
18
+ /** Step applied per zoom-in / zoom-out action and per keyboard shortcut. */
19
+ declare const ZOOM_STEP = 0.1;
20
+ //#endregion
21
+ export { ZOOM_MAX, ZOOM_MIN, ZOOM_STEP };
@@ -0,0 +1,21 @@
1
+ //#region src/utils/zoom.ts
2
+ /**
3
+ * Canonical zoom limits shared by every folio adapter (React, Vue, ...).
4
+ *
5
+ * Adapters must source their zoom range from here rather than hard-coding their
6
+ * own, so the reachable zoom span stays identical across framework hosts.
7
+ * Historically React clamped 0.25-4x while Vue clamped 0.5-2x; this module is
8
+ * the single source of truth that keeps them from drifting again.
9
+ *
10
+ * Note: the discrete zoom-level menu each adapter shows in its toolbar dropdown
11
+ * is a separate, deliberately curated subset (50-200%); it is not derived from
12
+ * these limits.
13
+ */
14
+ /** Minimum reachable zoom level (25%). */
15
+ const ZOOM_MIN = .25;
16
+ /** Maximum reachable zoom level (400%). */
17
+ const ZOOM_MAX = 4;
18
+ /** Step applied per zoom-in / zoom-out action and per keyboard shortcut. */
19
+ const ZOOM_STEP = .1;
20
+ //#endregion
21
+ export { ZOOM_MAX, ZOOM_MIN, ZOOM_STEP };