@plannotator/ui 0.32.0 → 0.33.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.
@@ -0,0 +1,24 @@
1
+ /**
2
+ * The default math renderer loader: KaTeX's JS only, fetched lazily.
3
+ *
4
+ * This module is the ONLY place in `@plannotator/ui` that names `katex` at
5
+ * runtime (`./math-eager` names it too, but a host chooses to import that).
6
+ * `./math` calls `loadDefaultMathRenderer` only when no host loader is
7
+ * registered (`setMathRendererLoader` / `configurePlannotatorUI({
8
+ * mathRendererLoader })`), so a host that registers one never runs the
9
+ * `import('katex')` below and never requests the chunk it produces.
10
+ *
11
+ * Keeping the import in its own module is what lets a bundler drop the chunk
12
+ * entirely: chunk emission is static, so a host that registers a loader and
13
+ * wants no KaTeX chunk from the package at all points this module at a stub
14
+ * (see HANDOFF.md "Lazy renderers and eager entries", the alias recipe). The
15
+ * stylesheet is deliberately NOT imported here; CSS loading stays the host's
16
+ * job (HANDOFF.md "Math rendering"), and a host that already serves
17
+ * `katex.min.css` would otherwise load it twice.
18
+ */
19
+
20
+ import type { MathRenderer } from './math';
21
+
22
+ export function loadDefaultMathRenderer(): Promise<MathRenderer> {
23
+ return import('katex').then((m) => m.default);
24
+ }
package/utils/math.ts CHANGED
@@ -11,12 +11,16 @@
11
11
  * call `loadMathRenderer()`, and re-render typeset once it resolves.
12
12
  *
13
13
  * This module deliberately has NO runtime import of `katex`: the only place
14
- * the dependency is named is the default loader's `import('katex')`, which a
15
- * chunking bundler turns into a lazy chunk and Plannotator's single-file
16
- * builds inline (the eager entry keeps it in the entry either way).
14
+ * the dependency is named is `./math-default-loader`'s `import('katex')`,
15
+ * which a chunking bundler turns into a lazy chunk and Plannotator's
16
+ * single-file builds inline (the eager entry keeps it in the entry either
17
+ * way). That default is called only while no host loader is registered, and
18
+ * it lives in its own module so a host that registers a loader can alias it
19
+ * away and drop the chunk (see HANDOFF.md "Lazy renderers and eager entries").
17
20
  */
18
21
 
19
22
  import type { KatexOptions } from 'katex';
23
+ import { loadDefaultMathRenderer } from './math-default-loader';
20
24
 
21
25
  /** The subset of KaTeX's API the renderer needs. `katex` itself satisfies it. */
22
26
  export interface MathRenderer {
@@ -25,13 +29,6 @@ export interface MathRenderer {
25
29
 
26
30
  export type MathRendererLoader = () => Promise<MathRenderer>;
27
31
 
28
- /**
29
- * Default loader: KaTeX's JS only. The stylesheet is deliberately NOT imported
30
- * here; CSS loading stays the host's job (see HANDOFF.md "Math rendering"),
31
- * and a host that already serves `katex.min.css` would otherwise load it twice.
32
- */
33
- const defaultMathRendererLoader: MathRendererLoader = () => import('katex').then((m) => m.default);
34
-
35
32
  /**
36
33
  * Who filled the slot: the eager entry (`./math-eager`), the lazy loader, or a
37
34
  * host calling `setMathRenderer` directly. Diagnostic for a host chasing a TeX
@@ -43,7 +40,13 @@ export type MathRendererSource = 'plannotator-math-eager' | 'loader' | 'host';
43
40
 
44
41
  let renderer: MathRenderer | null = null;
45
42
  let rendererSource: MathRendererSource | null = null;
46
- let loader: MathRendererLoader = defaultMathRendererLoader;
43
+ /**
44
+ * The host loader, or `null` while none is registered. `null` is the only
45
+ * state in which `loadMathRenderer()` reaches `loadDefaultMathRenderer` and
46
+ * its `import('katex')`; a registered loader is never backfilled by the
47
+ * default, not even after it rejects.
48
+ */
49
+ let loader: MathRendererLoader | null = null;
47
50
  let pending: Promise<MathRenderer> | null = null;
48
51
  const listeners = new Set<() => void>();
49
52
 
@@ -97,7 +100,7 @@ export function setMathRendererLoader(next: MathRendererLoader): void {
97
100
  export function loadMathRenderer(): Promise<MathRenderer> {
98
101
  if (renderer) return Promise.resolve(renderer);
99
102
  if (!pending) {
100
- const attempt = loader().then(
103
+ const attempt = (loader ? loader() : loadDefaultMathRenderer()).then(
101
104
  (loaded) => {
102
105
  setMathRenderer(loaded, 'loader');
103
106
  return loaded;
@@ -116,7 +119,7 @@ export function loadMathRenderer(): Promise<MathRenderer> {
116
119
  export function resetMathRenderer(): void {
117
120
  renderer = null;
118
121
  rendererSource = null;
119
- loader = defaultMathRendererLoader;
122
+ loader = null;
120
123
  pending = null;
121
124
  notify();
122
125
  }