@pie-element/element-player 0.1.2-next.2 → 0.1.2-next.20261002100925

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/README.md CHANGED
@@ -1,30 +1,6 @@
1
1
  # PIE Element Player
2
2
 
3
- Self-contained web components for rendering PIE elements, following the same architecture as `@pie-framework/pie-players`.
4
-
5
- ---
6
-
7
- ## ⚠️ IMPORTANT: NOT FOR PUBLISHING
8
-
9
- **This package is currently marked as `private` and should NOT be published to npm.**
10
-
11
- ### Build Issue
12
-
13
- The package has a dependency resolution issue that prevents it from building as a standalone library:
14
-
15
- - [element-loader.ts](src/lib/element-loader.ts) imports `$lib/element-imports` for local development mode
16
- - This import only exists in the element-demo app, not in this package
17
- - The import is marked as external in the build config as a workaround
18
- - For production use, this architecture needs to be refactored
19
-
20
- **Before publishing this package**, the following must be resolved:
21
-
22
- 1. Refactor the element-loader to not depend on app-specific imports
23
- 2. Either remove local development mode from the library OR provide a proper abstraction
24
- 3. Ensure the build completes successfully without external dependencies on non-existent modules
25
- 4. Remove the `"private": true` field from package.json
26
-
27
- **Issue tracked in**: Build fails with "Rollup failed to resolve import '$lib/element-imports'"
3
+ Self-contained web components for rendering PIE elements, following the same architecture as the `@pie-players/*` players in [pie-players](https://github.com/pie-framework/pie-players).
28
4
 
29
5
  ---
30
6
 
@@ -107,7 +83,6 @@ For elements with import maps:
107
83
 
108
84
  - Loads elements via dynamic ESM imports: `import('@pie-element/hotspot')`
109
85
  - Handles session state and user interactions
110
- - Manages math rendering internally (MathJax)
111
86
  - Emits `session-changed` events
112
87
  - Works with both React and Svelte elements
113
88
 
@@ -116,23 +91,50 @@ For elements with import maps:
116
91
  - Loads print exports: `import('@pie-element/hotspot/print')`
117
92
  - Stateless (no session management)
118
93
  - Optimized for print layouts
119
- - Manages math rendering internally (MathJax)
120
94
  - Role-based rendering (student/instructor)
121
95
 
122
96
  **All views:**
123
97
 
124
98
  - Use import maps for module resolution
125
99
  - Self-contained (no external setup needed)
126
- - Handle math rendering automatically
127
100
  - Support for both React and Svelte elements
128
101
 
102
+ ### Math rendering
103
+
104
+ The player typesets math through `window['@pie-lib/math-rendering'].renderMath`, read on every render. A renderer the host installs there before the player mounts, such as the legacy MathJax 3 one, is used and no MathJax 4 loads. Without one, the player installs a MathJax 4 renderer from `@pie-element/shared-math-rendering-mathjax`, which elements and later players on the page share.
105
+
106
+ ### Events
107
+
108
+ The player dispatches each event from `<pie-element-player>`, bubbling and composed. A bubble-phase listener on the player, on an ancestor or on `document` hears each event once, with `event.target` the player; a listener outside a shadow root that contains the player sees that root's host instead. The element's own `session-changed` stops at the element, and the player dispatches its copy in its place. A capture-phase listener on the player or above it also hears every `session-changed` the element dispatches, ahead of the player's copy, and should ignore events whose `event.composedPath()[0]` is not the player. That equals `event.target` when no shadow root lies between listener and player. A closed shadow root hides the player from both, so listen in the bubble phase there.
109
+
110
+ | Event | When | `detail` |
111
+ |---|---|---|
112
+ | `session-changed` | delivery: the learner changes the session, or the element re-reports a session the player set (below) | the element's detail, with `session` the new session |
113
+ | `model-changed` | author: the author edits the model | the whole model |
114
+ | `load-complete` | the element is mounted | `strategy`, `view`, `tagName` |
115
+ | `load-cancelled` | a newer load supersedes this one, or the load fails with an abort error (below) | `reason`, `strategy`, `view` |
116
+ | `player-error` | the load fails | `error`, `strategy`, `view`, `retry` |
117
+ | `build-state` | the load changes stage | `loading`, `error`, `stage`, and `strategy`, `view`, `retry` where known |
118
+ | `bundle-retry-status` | IIFE: a bundle build is polled; any strategy: the load fails with an abort error | the retry state |
119
+ | `bundle-meta` | IIFE: the bundle loads | the bundle's metadata |
120
+ | `controller-load` | a load completes, except a `preloaded` one that finds its tag defined (below) | `status`, `source`, `packageName`, `strategy`, `view`, `message` |
121
+ | `controller-changed` | IIFE delivery: the bundle's controller loads | the controller |
122
+
123
+ `session-changed` also fires with no learner action. Once the element has a model, the player sets `session` on it, and sets it again whenever the host assigns a different session. A report the element dispatches while that setter runs is dropped; one it dispatches after the setter returns is forwarded.
124
+
125
+ An abort error is a load error whose message contains `aborted`, whatever the strategy. The player then emits `bundle-retry-status` with state `cancelled`, `build-state` with stage `cancelled` and `load-cancelled`, in place of `player-error`.
126
+
127
+ `controller-load` reports `status` `loaded` in delivery view, where any other status fails the load. Author view can also report `missing` or `failed`, and print view reports `not-required` unless an IIFE bundle carries a controller.
128
+
129
+ A player removed from the document mid-load emits nothing more from that load, and re-attaching it starts a new one; a synchronous move keeps the load.
130
+
129
131
  ## Testing Elements Locally
130
132
 
131
133
  Use the existing demo commands to test elements:
132
134
 
133
135
  ```bash
134
- # Start demo server for Svelte elements
135
- bun cli dev:demo hotspot
136
+ # Start the element demo, then open http://localhost:5222/hotspot/deliver
137
+ bun cli dev:demo
136
138
  ```
137
139
 
138
140
  **Prerequisites:**
@@ -153,5 +155,5 @@ bun run build
153
155
 
154
156
  # Run element demo
155
157
  cd ../..
156
- bun cli dev:demo hotspot
158
+ bun cli dev:demo
157
159
  ```
package/dist/index.d.ts CHANGED
@@ -10,7 +10,7 @@
10
10
  */
11
11
  import './app.css';
12
12
  import './players/index.js';
13
- export type { ElementPlayerProps, PieController, Tab } from './lib/types.js';
13
+ export type { ElementPlayerProps, PieController } from './lib/types.js';
14
14
  export type { ElementPlayerStrategy, ElementPlayerView } from './lib/player-strategy.js';
15
15
  export type { RuntimeSupportCheck, RuntimeSupportStrategy, RuntimeSupportView, PieElementRuntimeSupport, } from './lib/runtime-support.js';
16
16
  export { normalizeRuntimeSupportCheck } from './lib/runtime-support.js';
@@ -4,7 +4,7 @@
4
4
  * Dynamically loads PIE elements from CDN and registers them as custom elements.
5
5
  * Based on the ESM loader pattern from pie-players.
6
6
  */
7
- import type { PieElementRuntimeSupport } from './runtime-support';
7
+ import type { PieElementRuntimeSupport } from './runtime-support.js';
8
8
  export type ElementModuleKind = 'delivery' | 'author' | 'print' | 'controller' | 'runtime-support';
9
9
  export interface ElementModuleResolveRequest {
10
10
  packagePath: string;
@@ -1,7 +1 @@
1
1
  export type MathRenderer = (element: HTMLElement) => void | Promise<void>;
2
- export interface MathRenderingAPI {
3
- renderMath: MathRenderer;
4
- wrapMath?: (latex: string) => string;
5
- unWrapMath?: (wrapped: string) => string;
6
- mmlToLatex?: (mathml: string) => string;
7
- }
@@ -18,9 +18,3 @@ export interface PieController {
18
18
  outcome?: (model: any, session: any, env: any) => Promise<any>;
19
19
  createCorrectResponseSession?: (model: any, env: any) => Promise<any>;
20
20
  }
21
- export interface Tab {
22
- id: string;
23
- label: string;
24
- description?: string;
25
- disabled?: boolean;
26
- }
@@ -1,7 +1,7 @@
1
- import { type ElementModuleResolver } from './element-loader';
2
- import { type IifeBundleRetryConfig, type IifeBundleRetryStatus, type IifeBundleLoadError, type LocalBundleMeta } from './iife-bundle-loader';
3
- import { type ElementPlayerStrategy, type ElementPlayerView } from './player-strategy';
4
- import { type PieElementRuntimeSupport, type RuntimeSupportCheck } from './runtime-support';
1
+ import { type ElementModuleResolver } from './element-loader.js';
2
+ import { type IifeBundleRetryConfig, type IifeBundleRetryStatus, type IifeBundleLoadError, type LocalBundleMeta } from './iife-bundle-loader.js';
3
+ import { type ElementPlayerStrategy, type ElementPlayerView } from './player-strategy.js';
4
+ import { type PieElementRuntimeSupport, type RuntimeSupportCheck } from './runtime-support.js';
5
5
  export interface UnifiedPlayerLoadRequest {
6
6
  strategy: string | null | undefined;
7
7
  view: string | null | undefined;
@@ -0,0 +1,179 @@
1
+ //#region ../shared/math-rendering-mathjax/dist/index.js
2
+ var e = "https://github.com/pie-framework/pie-players/blob/develop/docs/item-player/loading-strategies.md#one-mathjax-version-per-page", t = Symbol.for("@pie-element/shared-math-rendering-mathjax/unsupported-page");
3
+ function n(n, r) {
4
+ if (typeof window > "u") return;
5
+ let i = globalThis;
6
+ i[t] ??= {
7
+ logged: !1,
8
+ conditions: []
9
+ };
10
+ let a = i[t];
11
+ if (a.conditions.includes(n)) return;
12
+ a.conditions.push(n);
13
+ let o = `[math-rendering] Unsupported page (${n}): ${r}. PIE supports one MathJax major version per page; with MathJax 3 and 4 on one page, math rendering is best effort and may break. See ${e}`;
14
+ a.logged || (a.logged = !0, console.error(o)), window.dispatchEvent(new CustomEvent("pie-mathjax-version-conflict", { detail: {
15
+ condition: n,
16
+ message: o,
17
+ docsUrl: e
18
+ } }));
19
+ }
20
+ function r() {
21
+ let e = window.MathJax?.version;
22
+ return typeof e == "string" && e.startsWith("3.") ? e : void 0;
23
+ }
24
+ var i = "https://cdn.jsdelivr.net/npm/mathjax@4.1.3/tex-mml-chtml.js", a = {
25
+ parallelogram: "\\lower.2em{\\Huge\\unicode{x25B1}}",
26
+ overarc: "\\overparen",
27
+ napprox: "\\not\\approx",
28
+ longdiv: "\\enclose{longdiv}",
29
+ abs: ["\\left|#1\\right|", 1]
30
+ }, o = "[math-rendering] using $ is not advisable, please use $$..$$ or \\(...\\)", s = /\\\(|\\\[|\$\$|\\\$|\\begin\{|\\(?:eq)?ref\{/, c = /\\\(|\\\[|\$|\\begin\{|\\(?:eq)?ref\{/, l = /\\embed\{newLine\}\[\]/g, u = [
31
+ ["$$", "$$"],
32
+ ["$", "$"],
33
+ ["\\[", "\\]"],
34
+ ["\\(", "\\)"]
35
+ ], d = Symbol.for("@pie-element/shared-math-rendering-mathjax/loading"), f = "PIE-MJX-CHTML-styles", p = "MJX-CHTML-styles", m = [p, "MJX-SVG-styles"], h = 201;
36
+ function g(e) {
37
+ let t = [...e.matches("mjx-container") ? [e] : [], ...e.querySelectorAll("mjx-container")];
38
+ for (let e of t) for (let t of [e, ...e.querySelectorAll("[data-latex],[data-latex-item]")]) t.removeAttribute("data-latex"), t.removeAttribute("data-latex-item");
39
+ }
40
+ function _() {
41
+ return window.MathJax;
42
+ }
43
+ function v(e) {
44
+ for (let [t, n] of u) if (e.startsWith(t) && e.endsWith(n)) return e.substring(t.length, e.length - n.length);
45
+ return e;
46
+ }
47
+ function y(e) {
48
+ return v(e.includes("\\displaystyle") ? e.replace("\\displaystyle", "").trim() : e);
49
+ }
50
+ var b = "mathjax_ignore", x = "mathjax_process";
51
+ function S(e, t) {
52
+ let n = e.closest(`.${b}, .${x}`);
53
+ return n !== null && t.contains(n) && !n.classList.contains(x);
54
+ }
55
+ function C(e) {
56
+ for (let t of e.querySelectorAll("[data-latex]")) {
57
+ if (t.dataset.mathHandled || t.closest("mjx-container") || S(t, e)) continue;
58
+ let n = t.textContent;
59
+ n && (t.textContent = `\\(${y(n)}\\)`.replace(l, "\\newline "), t.dataset.mathHandled = "true");
60
+ }
61
+ }
62
+ function w(e, t) {
63
+ for (let t of e.querySelectorAll("math")) if (!t.closest("mjx-assistive-mml")) return !0;
64
+ return (t ? c : s).test(e.textContent ?? "");
65
+ }
66
+ function T(e) {
67
+ return new Promise((t, n) => {
68
+ let { useSingleDollar: r = !1, accessibility: s = !0, loadFonts: c = !0, srcUrl: l } = e, u = {
69
+ loader: {
70
+ load: s ? ["a11y/assistive-mml"] : [],
71
+ failed: (e) => n(e)
72
+ },
73
+ startup: {
74
+ typeset: !1,
75
+ ready: () => {
76
+ let e = _(), r = e?.startup, i = !!e?.version?.startsWith("4.");
77
+ i && E(e), r?.defaultReady?.(), i && D(r?.document), Promise.resolve(r?.promise).then(() => t(), n);
78
+ }
79
+ },
80
+ tex: { macros: { ...a } },
81
+ options: {
82
+ enableMenu: s,
83
+ menuOptions: { settings: {
84
+ assistiveMml: s,
85
+ enrich: !1,
86
+ inTabOrder: !1
87
+ } }
88
+ }
89
+ };
90
+ r && u.tex && (console.warn(o), u.tex.inlineMath = [["$", "$"], ["\\(", "\\)"]], u.tex.processEscapes = !0), c || (u.chtml = { fontURL: "" }), window.MathJax = u;
91
+ let d = document.createElement("script");
92
+ d.src = l || i, d.async = !0, d.onerror = () => n(/* @__PURE__ */ Error("Failed to load MathJax")), document.head.appendChild(d);
93
+ });
94
+ }
95
+ function E(e) {
96
+ let t = e?._?.output?.chtml_ts?.CHTML;
97
+ t && (t.STYLESHEETID = f);
98
+ }
99
+ function D(e) {
100
+ if (!e) return;
101
+ let t = /* @__PURE__ */ new WeakSet(), n = (e) => {
102
+ let n = e.typesetRoot;
103
+ !n || t.has(n) || (g(n), t.add(n));
104
+ };
105
+ e.addRenderAction?.("pie-strip-latex", h, (e) => {
106
+ for (let t of e.math ?? []) n(t);
107
+ return !1;
108
+ }, (e) => {
109
+ let t = e.typesetRoot;
110
+ return t && g(t), !1;
111
+ });
112
+ let r = e.outputJax?.chtmlStyles;
113
+ r?.id === p && (r.id = f), A();
114
+ }
115
+ function O(e) {
116
+ return e instanceof HTMLStyleElement && m.includes(e.id);
117
+ }
118
+ function k(e) {
119
+ n("foreign-output-stylesheet", `another MathJax added <style id="${e.id}"> to <head>`);
120
+ }
121
+ function A() {
122
+ let e = document.head, t = [...e.children].find(O);
123
+ if (t) {
124
+ k(t);
125
+ return;
126
+ }
127
+ let n = new MutationObserver((e) => {
128
+ for (let t of e) {
129
+ let e = [...t.addedNodes].find(O);
130
+ if (e) {
131
+ k(e), n.disconnect();
132
+ return;
133
+ }
134
+ }
135
+ });
136
+ n.observe(e, { childList: !0 });
137
+ }
138
+ function j(e) {
139
+ return new Promise((t, n) => {
140
+ let r = e.startup ?? {};
141
+ e.startup = r;
142
+ let i = r.ready;
143
+ r.ready = () => {
144
+ let e = _()?.startup;
145
+ i ? i.call(r) : e?.defaultReady?.(), Promise.resolve(e?.promise).then(() => t(), n);
146
+ };
147
+ });
148
+ }
149
+ function M(e) {
150
+ let t = _();
151
+ return t ? t.version ? t.startup?.promise ? Promise.resolve(t.startup.promise).then(() => void 0) : Promise.resolve() : j(t) : T(e);
152
+ }
153
+ function N(e) {
154
+ return M(e).then(() => {
155
+ typeof _()?.typesetPromise != "function" && console.warn("[mathjax-renderer] MathJax on this page has no typesetPromise; math stays untypeset.");
156
+ });
157
+ }
158
+ function P(e) {
159
+ let t = globalThis, n = t[d];
160
+ return n || (n = N(e), t[d] = n), n;
161
+ }
162
+ function F(e = {}) {
163
+ let t = e.useSingleDollar ?? !1;
164
+ return async (i) => {
165
+ if (typeof window > "u") return;
166
+ let a = r();
167
+ a && n("mathjax-3-global", `window.MathJax is MathJax ${a}`), C(i);
168
+ let o = P(e);
169
+ if (!w(i, t)) {
170
+ o.catch(() => {});
171
+ return;
172
+ }
173
+ await o;
174
+ let s = _();
175
+ await s?.startup?.promise, typeof s?.typesetPromise == "function" && (await s.typesetPromise([i]), g(i));
176
+ };
177
+ }
178
+ //#endregion
179
+ export { F as t };