@pie-players/pie-section-player 0.3.73 → 0.3.75
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 +395 -149
- package/dist/browser/assets/evaluation-worker-CORp9m0K.js +156459 -0
- package/dist/browser/chunks/ItemToolBar-jx38w99s-58defccc.js +1 -0
- package/dist/browser/chunks/PUA-tLuTiQ7--f2b27953.js +1 -0
- package/dist/browser/chunks/ToolCoordinator-cc2dc319.js +1 -0
- package/dist/browser/chunks/accents-BTUYmhn9-cafeb96e.js +1 -0
- package/dist/browser/chunks/accents-b-i-CngHZsLL-e0eb98fd.js +1 -0
- package/dist/browser/chunks/arabic-BzEHMVZD-30ac1ade.js +1 -0
- package/dist/browser/chunks/arrows-VjxlU-jv-2e17c192.js +1 -0
- package/dist/browser/chunks/base-dfd67c41.js +1 -0
- package/dist/browser/chunks/braille-BeWC_Ruq-a3bb8ef9.js +1 -0
- package/dist/browser/chunks/braille-d-Dk6J96GO-d832bfbf.js +1 -0
- package/dist/browser/chunks/browser-a3c32178.js +37 -0
- package/dist/browser/chunks/calculator-element-271c142f.js +13 -0
- package/dist/browser/chunks/calligraphic-Cew9cU3x-04cf0735.js +1 -0
- package/dist/browser/chunks/catalog-context-46d3e50e.js +1 -0
- package/dist/browser/chunks/catalog-owner-d602f784.js +1 -0
- package/dist/browser/chunks/cherokee-Cny3FYho-4da7d2f3.js +1 -0
- package/dist/browser/chunks/classPrivateFieldGet2-338e0179.js +1 -0
- package/dist/browser/chunks/cyrillic-CfCDulXU-5550df0b.js +1 -0
- package/dist/browser/chunks/cyrillic-ss-lU7bNGG9-12eb0188.js +1 -0
- package/dist/browser/chunks/defineProperty-a20a667d.js +1 -0
- package/dist/browser/chunks/devanagari-CDIz2h-r-18c38725.js +1 -0
- package/dist/browser/chunks/dist-41b39e7f.js +1 -0
- package/dist/browser/chunks/dist-59132a53.js +1 -0
- package/dist/browser/chunks/dist-60d7afef.js +1 -0
- package/dist/browser/chunks/dist-ca9b9622.js +1 -0
- package/dist/browser/chunks/double-struck-BpJEQk8y-500ce8dd.js +1 -0
- package/dist/browser/chunks/en-5ff22e17.js +1 -0
- package/dist/browser/chunks/es-a0ba6cb6.js +1 -0
- package/dist/browser/chunks/focus-trap-44913bf3.js +1 -0
- package/dist/browser/chunks/fraktur-rLEq9DEH-44cc14d8.js +1 -0
- package/dist/browser/chunks/greek-BlraJTyL-90ce8924.js +1 -0
- package/dist/browser/chunks/greek-ss-D-EN2PK0-91610739.js +1 -0
- package/dist/browser/chunks/hebrew-GiQZeybp-b583f555.js +1 -0
- package/dist/browser/chunks/latin-b-BhEnC7R2-d13e06ff.js +1 -0
- package/dist/browser/chunks/latin-bi-DqiIKv3U-1dec8705.js +1 -0
- package/dist/browser/chunks/latin-i-B1xtwaE1-21637466.js +1 -0
- package/dist/browser/chunks/latin-xfWFlLkD-5bcea5cf.js +1 -0
- package/dist/browser/chunks/logger-8b07fb72.js +1 -0
- package/dist/browser/chunks/marrows-DD1NgMQi-15b63755.js +1 -0
- package/dist/browser/chunks/math-DpWn1mbG-38eeb914.js +1 -0
- package/dist/browser/chunks/math-rendering-ready-9a0fd90a.js +1 -0
- package/dist/browser/chunks/mathjax-BKrHE4xs-3ca05bf6.js +232 -0
- package/dist/browser/chunks/module-0191e321.js +74 -0
- package/dist/browser/chunks/module-shim-58659a86.js +0 -0
- package/dist/browser/chunks/module-shim-b4470740.js +12 -0
- package/dist/browser/chunks/monospace-D116QD2a-98d484fd.js +1 -0
- package/dist/browser/chunks/monospace-ex-DcXpouKS-456b403c.js +1 -0
- package/dist/browser/chunks/monospace-l-Ct5wkMDs-f34a4a9e.js +1 -0
- package/dist/browser/chunks/mshapes-DCp86WSX-c0055952.js +1 -0
- package/dist/browser/chunks/nl-NL-364d61b9.js +1 -0
- package/dist/browser/chunks/nl-NL-8b7e6d4b.js +1 -0
- package/dist/browser/chunks/overlay-containment-edaaff13.js +1 -0
- package/dist/browser/chunks/overlay-placement-e8058232.js +1 -0
- package/dist/browser/chunks/phonetics-BwOCw2Y9-d2e3af59.js +1 -0
- package/dist/browser/chunks/phonetics-ss-CRtMn02f-579b6135.js +1 -0
- package/dist/browser/chunks/pie-api-client-687c319a.js +1 -0
- package/dist/browser/chunks/pointer-gesture-ce75f0a7.js +1 -0
- package/dist/browser/chunks/preload-helper-6ad28da3.js +1 -0
- package/dist/browser/chunks/provider-4c704118.js +1 -0
- package/dist/browser/chunks/rolldown-runtime-1287ba31.js +1 -0
- package/dist/browser/chunks/runtime-wcU7KOFU-ac86d7b8.js +8536 -0
- package/dist/browser/chunks/sanitize-svg-icon-b9082bba.js +3 -0
- package/dist/browser/chunks/sans-serif-BYPZKlE9-2efdbcd9.js +1 -0
- package/dist/browser/chunks/sans-serif-b-B0kRKiC--b5530dce.js +1 -0
- package/dist/browser/chunks/sans-serif-bi-DXWul6mu-5370dba4.js +1 -0
- package/dist/browser/chunks/sans-serif-ex-Boux1kMP-aa178f31.js +1 -0
- package/dist/browser/chunks/sans-serif-i-676RFaSO-2db54474.js +1 -0
- package/dist/browser/chunks/sans-serif-r-DrN9xdZt-0fc72eea.js +1 -0
- package/dist/browser/chunks/script-0ohehnXc-526904f4.js +1 -0
- package/dist/browser/chunks/shapes-BG47NodJ-d59b0eca.js +1 -0
- package/dist/browser/chunks/src-BcptuNS5-ed25d7fd.js +191 -0
- package/dist/browser/chunks/sre-0162a7a9.js +53 -0
- package/dist/browser/chunks/sre-engine-ace23548.js +1 -0
- package/dist/browser/chunks/sre-engine-jd8cc08x-42d270e5.js +1 -0
- package/dist/browser/chunks/sre-locales-112320af.js +1 -0
- package/dist/browser/chunks/symbols-BqnUxf_t-83087e87.js +1 -0
- package/dist/browser/chunks/symbols-b-i-eg9k5hmF-9c461ac2.js +1 -0
- package/dist/browser/chunks/tool-annotation-toolbar-997438b4.js +249 -0
- package/dist/browser/chunks/tool-answer-eliminator-35483abd.js +13 -0
- package/dist/browser/chunks/tool-color-scheme-b7de5cdf.js +26 -0
- package/dist/browser/chunks/tool-dictionary-cecff3b4.js +7 -0
- package/dist/browser/chunks/tool-graph-cb0338e8.js +11 -0
- package/dist/browser/chunks/tool-host-contract-b93b482c.js +1 -0
- package/dist/browser/chunks/tool-instance-id-2a92deb0.js +1 -0
- package/dist/browser/chunks/tool-line-reader-f8ef3c6a.js +62 -0
- package/dist/browser/chunks/tool-periodic-table-43b133b8.js +153 -0
- package/dist/browser/chunks/tool-picture-dictionary-33721e91.js +4 -0
- package/dist/browser/chunks/tool-protractor-23f77028.js +17 -0
- package/dist/browser/chunks/tool-ruler-1d9a03a6.js +15 -0
- package/dist/browser/chunks/tool-tts-inline-98c2ce7a.js +179 -0
- package/dist/browser/chunks/tts-runtime-config-a7ab1ad4.js +194 -0
- package/dist/browser/chunks/variants-2LRNhOUP-966fc49d.js +1 -0
- package/dist/browser/chunks/versioned-tag-54a76be9.js +1 -0
- package/dist/browser/pie-section-player.js +1727 -0
- package/dist/browser.d.ts +10 -0
- package/dist/chunks/ItemToolBar-jx38w99s-1287ba31.js +28 -0
- package/dist/chunks/module-shim-58659a86.js +2129 -0
- package/dist/chunks/{nl-NL-9312c316.js → nl-NL-364d61b9.js} +9 -26
- package/dist/chunks/sre-engine-jd8cc08x-42d270e5.js +8 -0
- package/dist/components/shared/composition.d.ts +3 -2
- package/dist/components/shared/framework-error-latch.d.ts +32 -0
- package/dist/components/shared/host-element.d.ts +10 -0
- package/dist/components/shared/kernel-host-default-body.d.ts +14 -0
- package/dist/components/shared/layout-host-methods.d.ts +385 -0
- package/dist/components/shared/missing-tool-providers.d.ts +16 -0
- package/dist/components/shared/player-preload.d.ts +14 -10
- package/dist/components/shared/section-player-backend-delivery.d.ts +1 -1
- package/dist/components/shared/section-player-card-context.d.ts +5 -1
- package/dist/components/shared/section-player-host-runtime.d.ts +32 -19
- package/dist/components/shared/section-player-layout-context.d.ts +77 -0
- package/dist/components/shared/section-player-own-event.d.ts +10 -0
- package/dist/components/shared/section-player-runtime-callbacks.d.ts +1 -1
- package/dist/components/shared/section-player-shell-layout.svelte.d.ts +3 -11
- package/dist/components/shared/section-player-view-state.d.ts +6 -1
- package/dist/components/shared/toolkit-ready-wait.d.ts +16 -0
- package/dist/contracts/host-hooks.d.ts +4 -12
- package/dist/contracts/host-hooks.js +0 -0
- package/dist/contracts/runtime-host-contract.d.ts +0 -5
- package/dist/contracts/runtime-host-contract.js +0 -0
- package/dist/controllers/SectionController.d.ts +14 -0
- package/dist/controllers/toolkit-section-contracts.d.ts +1 -17
- package/dist/controllers/types.d.ts +25 -11
- package/dist/item-section/index.d.ts +22 -0
- package/dist/item-section/index.js +37 -0
- package/dist/pie-section-player.d.ts +4 -6
- package/dist/pie-section-player.js +22006 -41076
- package/dist/policies/index.d.ts +5 -16
- package/dist/policies/index.js +17 -0
- package/dist/policies/types.d.ts +0 -4
- package/package.json +33 -68
- package/dist/chunks/module-a516757f.js +0 -73997
- package/dist/chunks/nl-NL-ef6dd604.js +0 -505
- package/dist/chunks/pie-api-client-22de9d9c.js +0 -168
- package/dist/chunks/rolldown-runtime-1287ba31.js +0 -20
- package/dist/chunks/sre-0162a7a9.js +0 -17637
- package/dist/components/item-shell-element.d.ts +0 -1
- package/dist/components/shared/shell-registration.d.ts +0 -55
- package/dist/contracts/layout-contract.d.ts +0 -17
- package/dist/contracts/layout-parity-metadata.d.ts +0 -4
- package/dist/contracts/public-events.d.ts +0 -93
- package/dist/contracts/stages.d.ts +0 -10
- package/dist/policies/guards.d.ts +0 -2
- package/dist/utils/z-index.d.ts +0 -5
package/README.md
CHANGED
|
@@ -6,7 +6,9 @@ Section rendering package with layout custom elements:
|
|
|
6
6
|
- `pie-section-player-vertical`
|
|
7
7
|
- `pie-section-player-tabbed`
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
A host that arranges the section itself builds its layout from
|
|
10
|
+
`pie-section-player-kernel-host` and the two panes; see
|
|
11
|
+
[Custom layout authoring](#custom-layout-authoring).
|
|
10
12
|
|
|
11
13
|
## Install
|
|
12
14
|
|
|
@@ -33,11 +35,16 @@ opt-out.
|
|
|
33
35
|
import "@pie-players/pie-section-player";
|
|
34
36
|
```
|
|
35
37
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
+
The entrypoints under `@pie-players/pie-section-player/components/*` load one
|
|
39
|
+
element each, together with every element it renders: a layout entry also
|
|
40
|
+
registers the cards, panes and shell. They choose which layouts a host loads; the
|
|
41
|
+
tag names stay fixed.
|
|
38
42
|
|
|
39
|
-
|
|
40
|
-
|
|
43
|
+
The entries are bundler-only: they import `@pie-players/pie-item-player`,
|
|
44
|
+
`@pie-players/pie-default-tool-loaders` and `speech-rule-engine`, with the
|
|
45
|
+
engine's JSON locale tables, by bare specifier and without import attributes.
|
|
46
|
+
Items render through the host's one `@pie-players/pie-item-player`, which this
|
|
47
|
+
package depends on at its own version.
|
|
41
48
|
|
|
42
49
|
## SectionController
|
|
43
50
|
|
|
@@ -59,17 +66,40 @@ the per-method contract.
|
|
|
59
66
|
|
|
60
67
|
```ts
|
|
61
68
|
const host = document.querySelector("pie-section-player-splitpane") as any;
|
|
62
|
-
const controller = await host.waitForSectionController
|
|
69
|
+
const controller = await host.waitForSectionController(5000);
|
|
63
70
|
```
|
|
64
71
|
|
|
65
72
|
`waitForSectionController(timeoutMs)` resolves when the layout CE has wired
|
|
66
73
|
its controller (the same anchor `pie-stage-change` reaches with
|
|
67
|
-
`detail.stage === "engine-ready"`)
|
|
68
|
-
already passed the readiness anchor
|
|
74
|
+
`detail.stage === "engine-ready"`), or with `null` once `timeoutMs` passes.
|
|
75
|
+
Use `getSectionController()` if you've already passed the readiness anchor
|
|
76
|
+
synchronously.
|
|
77
|
+
|
|
78
|
+
The layout elements define their host methods from the moment they are
|
|
79
|
+
created, so a host can call them before the element mounts. Until it mounts,
|
|
80
|
+
`waitForSectionController` waits, `getSectionController()` returns `null`, the
|
|
81
|
+
navigation methods return `false`, and `getSnapshot()` and the `select*` reads
|
|
82
|
+
return `null` (`pie-section-player-kernel-host` returns its bootstrapping
|
|
83
|
+
snapshot).
|
|
69
84
|
|
|
70
85
|
### Session lifecycle
|
|
71
86
|
|
|
72
|
-
|
|
87
|
+
Set `session` with `section` to restore a section. The controller created for
|
|
88
|
+
that section applies it in replace mode in place of hydrating from the
|
|
89
|
+
persistence strategy, before the controller is published, so the first
|
|
90
|
+
composition, `engine-ready` and every reader see it. The strategy still receives
|
|
91
|
+
every `persist()`.
|
|
92
|
+
|
|
93
|
+
A later assignment applies through `applySession(value, { mode: "replace" })`
|
|
94
|
+
under the rules `<pie-item-player>` applies to its `session`: a value equal to
|
|
95
|
+
the current session is a no-op, so echoing `session-changed` back is safe, and an
|
|
96
|
+
item session with neither a response value nor a response field leaves one that
|
|
97
|
+
holds responses in place. `null` after creation is a no-op. A `section` change
|
|
98
|
+
without a `session` assignment hydrates the new controller from the strategy.
|
|
99
|
+
Reading `session` returns the assigned value until the controller is published,
|
|
100
|
+
and a fresh `getSession()` snapshot after.
|
|
101
|
+
|
|
102
|
+
Driving the controller directly:
|
|
73
103
|
|
|
74
104
|
```ts
|
|
75
105
|
controller?.configureSessionPersistence?.({ context, strategy });
|
|
@@ -97,11 +127,25 @@ policy](#js-api-example-for-advanced-host-policy). Key event types:
|
|
|
97
127
|
|
|
98
128
|
- `item-selected` — item navigation within the current section.
|
|
99
129
|
- `item-session-data-changed` / `item-session-meta-changed` — per-item
|
|
100
|
-
session updates the persistence layer should observe.
|
|
101
|
-
|
|
130
|
+
session updates the persistence layer should observe. `sectionId` names the
|
|
131
|
+
section. `elementId` names the reporting element when the change carries one,
|
|
132
|
+
and `complete` is then that element's own. A commit carries
|
|
133
|
+
`sessionCommitReason` (see [Commit at a section
|
|
134
|
+
boundary](#commit-at-a-section-boundary)).
|
|
135
|
+
- `item-complete-changed` — an item's completion flipped. An item is complete
|
|
136
|
+
when every element that has reported its completion is complete. A report
|
|
137
|
+
without `elementId`, and a restored session's item-level `complete`, set the
|
|
138
|
+
item's completion directly. A session restored through `applySession`
|
|
139
|
+
without `complete` is complete when it holds a response. A passage's own
|
|
140
|
+
`session-changed` stays inside its shell: a passage holds no response.
|
|
141
|
+
- `content-loaded` — passage / item / rubric finished loading. Carries
|
|
142
|
+
`contentKind`, `itemId`, and `canonicalItemId`.
|
|
102
143
|
- `section-loading-complete` — every renderable in the section finished
|
|
103
144
|
loading.
|
|
104
145
|
- `section-items-complete-changed` — aggregate completion flip.
|
|
146
|
+
- `section-error` — an item player failed (`source: "item-player"`), or the
|
|
147
|
+
section runtime did (`source: "section-runtime"`), a rejected element warmup
|
|
148
|
+
included, which leaves the items unmounted.
|
|
105
149
|
- `section-navigation-change` — the controller's section identity changed.
|
|
106
150
|
- `formative-try-recorded` — a learner checked an answer.
|
|
107
151
|
- `formative-reveal-changed` — the reveal state changed without a Try: a learner
|
|
@@ -119,6 +163,20 @@ policy](#js-api-example-for-advanced-host-policy). Key event types:
|
|
|
119
163
|
- `timed-media-invalid` — authored `timedMedia` that cannot be delivered; the
|
|
120
164
|
section renders without cue behavior.
|
|
121
165
|
|
|
166
|
+
The helpers' default event sets leave out `formative-try-recorded`,
|
|
167
|
+
`formative-reveal-changed`, `section-mastery-changed` and
|
|
168
|
+
`timed-media-audio-started`. Name them in `subscribeItemEvents({ eventTypes })`,
|
|
169
|
+
or subscribe through `subscribeSectionEvents`.
|
|
170
|
+
|
|
171
|
+
Item-scoped events carry both id forms, and both are always populated.
|
|
172
|
+
`itemId` is the bare `item.id` — the form the map returned by
|
|
173
|
+
`getItemSessionsByItemId()` is keyed by, and the form `applySession` expects.
|
|
174
|
+
`canonicalItemId` is that item's adapter identifier, and falls back to `itemId`
|
|
175
|
+
when the section was not built from an adapter or no adapter ref matches it.
|
|
176
|
+
Correlate with formative policy and `runtime.player.resolveBackend` by
|
|
177
|
+
`canonicalItemId`; reach the session by `itemId`. `content-loaded` and
|
|
178
|
+
`item-player-error` both carry the pair.
|
|
179
|
+
|
|
122
180
|
### Formative delivery
|
|
123
181
|
|
|
124
182
|
Set `formative` on the section and the player renders a check-answer control per
|
|
@@ -145,12 +203,12 @@ projected over the section env — with `role: "instructor"` under
|
|
|
145
203
|
`feedback: "solution"` — and the element draws the rest. Only that item's env
|
|
146
204
|
changes; its neighbours stay editable. A retry withdraws the projection.
|
|
147
205
|
|
|
148
|
-
Read the resolved state from `getFormativeProjection()`, or
|
|
149
|
-
`
|
|
150
|
-
same handle:
|
|
206
|
+
Read the resolved state from `getFormativeProjection()`, or from
|
|
207
|
+
`composition.formative` in a `composition-changed` event's detail. Drive it from a
|
|
208
|
+
host through the same handle:
|
|
151
209
|
|
|
152
210
|
```ts
|
|
153
|
-
const controller = await host.waitForSectionController
|
|
211
|
+
const controller = await host.waitForSectionController(5000);
|
|
154
212
|
// The learner's actions, budget-respecting.
|
|
155
213
|
controller?.recordFormativeTry?.({ itemId, outcomes }); // outcomes from provideScore()
|
|
156
214
|
controller?.retryFormativeItem?.({ itemId });
|
|
@@ -225,7 +283,7 @@ with its own player registers its own port instead, and that port outranks the
|
|
|
225
283
|
card's discovery for as long as it is attached:
|
|
226
284
|
|
|
227
285
|
```ts
|
|
228
|
-
const controller = await host.waitForSectionController
|
|
286
|
+
const controller = await host.waitForSectionController(5000);
|
|
229
287
|
// No `renderableId`: a host is asserting its own port, where a renderable's adapter
|
|
230
288
|
// has to name itself and is ignored unless it is the resolved stimulus.
|
|
231
289
|
controller?.attachMediaTimeSource?.(myThirdPartyPort);
|
|
@@ -264,14 +322,10 @@ for the contract and the decision record.
|
|
|
264
322
|
|
|
265
323
|
## Usage
|
|
266
324
|
|
|
267
|
-
Import the
|
|
325
|
+
Import the package root, which registers every section-player element:
|
|
268
326
|
|
|
269
327
|
```ts
|
|
270
|
-
import '@pie-players/pie-section-player
|
|
271
|
-
import '@pie-players/pie-section-player/components/section-player-vertical-element';
|
|
272
|
-
import '@pie-players/pie-section-player/components/section-player-tabbed-element';
|
|
273
|
-
import '@pie-players/pie-section-player/components/section-player-item-card-element';
|
|
274
|
-
import '@pie-players/pie-section-player/components/section-player-passage-card-element';
|
|
328
|
+
import '@pie-players/pie-section-player';
|
|
275
329
|
```
|
|
276
330
|
|
|
277
331
|
Render in HTML/Svelte/JSX:
|
|
@@ -280,29 +334,51 @@ Render in HTML/Svelte/JSX:
|
|
|
280
334
|
<pie-section-player-splitpane></pie-section-player-splitpane>
|
|
281
335
|
```
|
|
282
336
|
|
|
283
|
-
Set complex values (`runtime`, `section`, `
|
|
337
|
+
Set complex values (`runtime`, `section`, `session`) as JS properties. `env` is a
|
|
338
|
+
`runtime` field (`runtime.env`); the layout elements have no `env` property.
|
|
339
|
+
|
|
340
|
+
Set `runtime` no later than `section`. When the player builds its own
|
|
341
|
+
coordinator, the section's arrival rebuilds that coordinator from the current
|
|
342
|
+
`runtime`, so both can be set a tick after the element mounts. Once the section
|
|
343
|
+
has initialized, a change to `runtime.tools`, `runtime.assessmentId`,
|
|
344
|
+
`runtime.accessibility`, `runtime.lazyInit`, `tool-config-strictness` or
|
|
345
|
+
`toolRegistry` is reported once in the console and does not reach that
|
|
346
|
+
coordinator; `runtime.tools.pnpEnforcement` still applies. Change a running
|
|
347
|
+
coordinator through the one `toolkit-ready` carries, with
|
|
348
|
+
`updateToolConfig(...)` or `updateToolsPlacement(...)`, or pass your own as
|
|
349
|
+
`runtime.coordinator`.
|
|
284
350
|
|
|
285
351
|
## Runtime Inputs
|
|
286
352
|
|
|
287
|
-
|
|
353
|
+
The layout elements (`pie-section-player-splitpane`,
|
|
354
|
+
`pie-section-player-vertical`, `pie-section-player-tabbed`) support:
|
|
288
355
|
|
|
289
356
|
- `runtime` (object): primary coordinator/tools/player runtime bundle
|
|
290
357
|
- `section` (object): assessment section payload
|
|
291
|
-
- `
|
|
358
|
+
- `session` (object, JS property only): the section's session, a `SectionControllerSessionState`; see [Session lifecycle](#session-lifecycle)
|
|
359
|
+
- `assessment` (object, JS property only): the `AssessmentEntity` whose `personalNeedsProfile` and `settings` tool policy reads, forwarded to the coordinator the player builds. A coordinator passed in `runtime` is the host's to bind with `updateAssessment`. A section's own `personalNeedsProfile` is not read, and the player warns once when it finds one
|
|
292
360
|
- `debug` (boolean-like): verbose debug logging control (`"true"` enables, `"false"`/`"0"` disables)
|
|
293
361
|
- `toolbar-position` (string): `top|right|bottom|left|none`
|
|
294
362
|
- `narrow-layout-breakpoint` (number, optional): viewport width in px below which the layout collapses (split pane: single column; vertical: toolbar moves to top). Clamped to 400–2000; default 1100.
|
|
295
363
|
- `content-max-width-no-passage` (number, optional): max width in px when no passages exist. Clamped to 320–2200. Unset by default (layout uses available width).
|
|
296
364
|
- `content-max-width-with-passage` (number, optional): max width in px when passages are present. Clamped to 320–2200. Unset by default (layout uses available width).
|
|
297
|
-
- `split-pane-min-region-width` (number, optional): splitpane minimum pane width in px. Clamped to 160–1200. Unset by default (split bounds stay at 20–80).
|
|
298
|
-
- `split-pane-collapse-strategy` (string, optional): splitpane stacked-mode strategy. Supported values: `tabbed` (default) and `vertical`.
|
|
365
|
+
- `split-pane-min-region-width` (number, optional): splitpane minimum pane width in px. Clamped to 160–1200. Unset by default (split bounds stay at 20–80). Splitpane only.
|
|
366
|
+
- `split-pane-collapse-strategy` (string, optional): splitpane stacked-mode strategy. Supported values: `tabbed` (default) and `vertical`. Splitpane only.
|
|
299
367
|
- `base-heading-level` (number, optional): the heading level this player's card headings occupy, and the level every descendant's outline derives from. Clamped to 1–6; default 2. See [Heading structure](#heading-structure).
|
|
300
|
-
- `show-toolbar` (boolean-like): accepts `true/false` and common string forms (`"true"`, `"false"`, `"1"`, `"0"`, `"yes"`, `"no"`)
|
|
368
|
+
- `show-toolbar` (boolean-like): accepts `true/false` and common string forms (`"true"`, `"false"`, `"1"`, `"0"`, `"yes"`, `"no"`); default `false`, so tools placed at `section` level render only when it is `true`
|
|
369
|
+
- `locale` (string, optional): BCP-47 locale for the player's own interface text. Unset renders `en-US`.
|
|
370
|
+
- `runtime.contentLanguage` (string, optional, `runtime` only): BCP-47 language of the content where its markup names none, which read-aloud speaks in and picks catalog cards by. A `lang` between the content and its card wins; unset reads `en-US`. `locale` never sets it.
|
|
371
|
+
- `nds-icons` (boolean): opt in to NDS icon buttons.
|
|
372
|
+
- `tool-config-strictness` (string, optional): `off|warn|error` for tool-config validation; default `error`.
|
|
373
|
+
- `split-pane-initial-passage-width` (number, optional): splitpane passage pane width in percent at mount. Clamped to 20–80; default 50. Splitpane only.
|
|
374
|
+
- `iife-bundle-host` (string, optional): bundle host for the IIFE element pre-warm when `runtime.player.loaderOptions.bundleHost` is unset.
|
|
301
375
|
- Host extension props (JS properties only): `toolRegistry`, `sectionHostButtons`, `itemHostButtons`, `passageHostButtons`, `hooks`
|
|
302
376
|
|
|
303
|
-
When viewport
|
|
304
|
-
vertical layout hosts normalize section toolbar placement to `top`.
|
|
305
|
-
`left`, `right`, `bottom`, and `none` values.
|
|
377
|
+
When the viewport is no wider than `narrow-layout-breakpoint` (default 1100px),
|
|
378
|
+
splitpane and vertical layout hosts normalize section toolbar placement to `top`.
|
|
379
|
+
This includes `left`, `right`, `bottom`, and `none` values. Separately, the shell
|
|
380
|
+
moves a `left` or `right` toolbar to `top` at a fixed 1100px, so with a smaller
|
|
381
|
+
breakpoint side toolbars still move to the top from 1100px down.
|
|
306
382
|
|
|
307
383
|
`hooks.cardTitleFormatter` remains active across responsive splitpane transitions (split -> stacked and stacked -> split), because title rendering is provided through shared card context rather than layout-specific state.
|
|
308
384
|
|
|
@@ -384,10 +460,7 @@ hooks for theming:
|
|
|
384
460
|
- `pie-section-player-tab--active`
|
|
385
461
|
- `pie-section-player-tab-panel`
|
|
386
462
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
- `data-pie-purpose="passage-label"` and alias class `passage-label`
|
|
390
|
-
- `data-pie-purpose="item-label"` and alias class `item-label`
|
|
463
|
+
Tabs also carry `data-pie-purpose="passage-label"` and `data-pie-purpose="item-label"`.
|
|
391
464
|
|
|
392
465
|
Tab colors, spacing, and track geometry can be themed via CSS variables:
|
|
393
466
|
`--pie-section-player-tab-color`, `--pie-section-player-tab-background`,
|
|
@@ -503,14 +576,14 @@ mountable-but-unoccupied result, not an error.
|
|
|
503
576
|
The intended usage model is:
|
|
504
577
|
|
|
505
578
|
- **CE props for default/standard flows (roughly 90% use cases)**:
|
|
506
|
-
- `
|
|
579
|
+
- `section`, `section-id`, `attempt-id`, `debug`, `locale`, `nds-icons`, `tool-config-strictness`
|
|
507
580
|
- `show-toolbar`, `toolbar-position`, `narrow-layout-breakpoint`
|
|
508
|
-
- `content-max-width-no-passage`, `content-max-width-with-passage`, `split-pane-min-region-width`, `split-pane-collapse-strategy`
|
|
581
|
+
- `content-max-width-no-passage`, `content-max-width-with-passage`, and on splitpane `split-pane-min-region-width`, `split-pane-collapse-strategy`
|
|
509
582
|
- **JS API for advanced customization**:
|
|
510
583
|
- Get the controller handle via `getSectionController()` or `waitForSectionController()` (preferred)
|
|
511
584
|
- Listen for `pie-stage-change` and filter on `detail.stage === "engine-ready"` for an event-driven entry point
|
|
512
585
|
- Apply custom policy/gating in host code (for example, domain-specific `canNext` based on controller events like `section-items-complete-changed`)
|
|
513
|
-
- Compose forward/backward eligibility in host code using `
|
|
586
|
+
- Compose forward/backward eligibility in host code using `getSnapshot().navigation` + host state; there is intentionally no separate parallel CE gating API for this
|
|
514
587
|
- Inject custom toolbar tooling with `toolRegistry` and optional host button arrays (`sectionHostButtons`, `itemHostButtons`, `passageHostButtons`)
|
|
515
588
|
- Register host callbacks via `hooks` (for example `hooks.cardTitleFormatter`)
|
|
516
589
|
|
|
@@ -534,9 +607,9 @@ Advanced runtime configuration is supplied through the `runtime` object. Set pla
|
|
|
534
607
|
|
|
535
608
|
Hosts can configure item-player backend delivery once at the section-player
|
|
536
609
|
runtime level. Section-player derives a concrete `backend` prop for each
|
|
537
|
-
embedded item player before it renders the item. This is intended for hosts
|
|
538
|
-
|
|
539
|
-
|
|
610
|
+
embedded item player before it renders the item. This is intended for hosts
|
|
611
|
+
that need server-processed PIE models and server scoring without querying every
|
|
612
|
+
nested `<pie-item-player>`.
|
|
540
613
|
|
|
541
614
|
```ts
|
|
542
615
|
import type {
|
|
@@ -577,6 +650,10 @@ each embedded item player. Static delivery fields such as `baseUrl`, `auth`,
|
|
|
577
650
|
`endpoints`, `assignmentId`, and `autosave` are preserved. Use `assignmentId`
|
|
578
651
|
for shared attempt/player identity.
|
|
579
652
|
|
|
653
|
+
An enabled `backend.delivery` also sets `hosted: true` on each embedded item
|
|
654
|
+
player unless `runtime.player.hosted` is set, so the item players load no
|
|
655
|
+
element controllers and render the models the server returns.
|
|
656
|
+
|
|
580
657
|
`runtime.player.resolveBackend` is a section-player-reserved key. It is called
|
|
581
658
|
with `{ itemId, canonicalItemId, item, itemIndex, itemSession, sectionId, env,
|
|
582
659
|
baseBackend }` and is stripped before props reach `<pie-item-player>`. Use it
|
|
@@ -594,12 +671,73 @@ backend config is preserved.
|
|
|
594
671
|
This backend delivery config is separate from the element-loader backend used
|
|
595
672
|
for IIFE/ESM bundle preloading.
|
|
596
673
|
|
|
674
|
+
### Preloaded elements
|
|
675
|
+
|
|
676
|
+
With `runtime.playerType: "preloaded"` the section player loads no element
|
|
677
|
+
code. Its pre-warm asserts that every tag the section's items and passages name
|
|
678
|
+
is registered, so the host registers the elements first:
|
|
679
|
+
|
|
680
|
+
```ts
|
|
681
|
+
import { registerPreloadedElements } from "@pie-players/pie-item-player/preloaded";
|
|
682
|
+
import * as delivery from "@pie-element/multiple-choice/browser/delivery";
|
|
683
|
+
import * as controller from "@pie-element/multiple-choice/browser/controller";
|
|
684
|
+
import manifest from "../package.json"; // pins "@pie-element/multiple-choice" exactly
|
|
685
|
+
|
|
686
|
+
registerPreloadedElements(
|
|
687
|
+
[
|
|
688
|
+
{
|
|
689
|
+
tag: "pie-element-multiple-choice",
|
|
690
|
+
package: "@pie-element/multiple-choice",
|
|
691
|
+
version: manifest.dependencies["@pie-element/multiple-choice"],
|
|
692
|
+
element: delivery,
|
|
693
|
+
controller,
|
|
694
|
+
},
|
|
695
|
+
],
|
|
696
|
+
{ math: { assetRoot: "https://assets.example.com/npm" } },
|
|
697
|
+
);
|
|
698
|
+
|
|
699
|
+
sectionPlayer.runtime = { ...sectionPlayer.runtime, playerType: "preloaded" };
|
|
700
|
+
```
|
|
701
|
+
|
|
702
|
+
- Register before the section player mounts. A tag missing at pre-warm leaves
|
|
703
|
+
the items unmounted and raises a non-recoverable `element-preload` framework
|
|
704
|
+
error.
|
|
705
|
+
- Install element packages with `npm install --save-exact`. npm otherwise saves
|
|
706
|
+
a caret range, which registration rejects as a `version`, and which a fresh
|
|
707
|
+
install can resolve to another release line: `^13.4.0-next.15` resolves to
|
|
708
|
+
the legacy `13.4.4`, which has no `./browser/*` modules.
|
|
709
|
+
- Install every pie-elements-ng package from one release, in one install from
|
|
710
|
+
the same dist-tag, and upgrade them together. Elements whose `./browser/*`
|
|
711
|
+
builds typeset on `window.MathJax` share the MathJax the first of them loads,
|
|
712
|
+
in the build and configuration of that element's release, so in a mixed set
|
|
713
|
+
an element can typeset with a MathJax it was not built for. Elements that
|
|
714
|
+
bundle their own MathJax share none
|
|
715
|
+
([One MathJax version per page](../../docs/item-player/loading-strategies.md#one-mathjax-version-per-page)).
|
|
716
|
+
- Pass `math.assetRoot`, an npm root serving the fonts and speech the elements'
|
|
717
|
+
bundled MathJax loads, or `math.assetUrls`, each file's URL; without either,
|
|
718
|
+
elements on adapter 0.1.3 or later render without web fonts and speech
|
|
719
|
+
([MathJax assets](../../docs/item-player/loading-strategies.md#mathjax-assets)).
|
|
720
|
+
- Register one version per package. The players align every authored version
|
|
721
|
+
of a package to the registered one, and registering a second version throws.
|
|
722
|
+
- Register each package's `controller` unless the item players are hosted
|
|
723
|
+
(`runtime.player.hosted`, or an enabled `runtime.player.backend.delivery`).
|
|
724
|
+
A player that is not hosted runs `model()` in the browser and warns for each
|
|
725
|
+
tag registered without one.
|
|
726
|
+
- Only `@pie-element/*` builds from pie-elements-ng publish
|
|
727
|
+
`./browser/delivery` and `./browser/controller`.
|
|
728
|
+
- Under TypeScript, the `package.json` import needs `resolveJsonModule`, and a
|
|
729
|
+
package version that ships no declarations for `./browser/*` needs a
|
|
730
|
+
`declare module` shim for those subpaths.
|
|
731
|
+
|
|
732
|
+
See [`strategy="preloaded"`](../../docs/item-player/loading-strategies.md#strategypreloaded)
|
|
733
|
+
for the registration contract.
|
|
734
|
+
|
|
597
735
|
### Host-owned focus
|
|
598
736
|
|
|
599
737
|
Section-player does not move focus on behalf of host-level affordances such
|
|
600
738
|
as "Skip to Main", nor does it make passage/question containers tab stops.
|
|
601
739
|
Hosts own page chrome, skip links, landmarks, and any special focus placement.
|
|
602
|
-
For example,
|
|
740
|
+
For example, a host shell can focus its own
|
|
603
741
|
`main#main-content`; the next Tab then follows the browser's natural order
|
|
604
742
|
into the first actionable control rendered inside the section player.
|
|
605
743
|
|
|
@@ -615,11 +753,16 @@ sequential keyboard navigation.
|
|
|
615
753
|
</main>
|
|
616
754
|
```
|
|
617
755
|
|
|
618
|
-
**
|
|
619
|
-
|
|
756
|
+
**Policy fields.** The layout accepts a partial `policies` object: every
|
|
757
|
+
unset field, a missing section included, takes its value from
|
|
758
|
+
`DEFAULT_SECTION_PLAYER_POLICIES`.
|
|
620
759
|
|
|
621
|
-
- `readiness.mode` (`"progressive"` | `"strict"`) —
|
|
622
|
-
|
|
760
|
+
- `readiness.mode` (`"progressive"` | `"strict"`) — the mode the layout
|
|
761
|
+
kernel gates readiness by. Both modes
|
|
762
|
+
hold the `interactive` stage and `pie-loading-complete` until the section's
|
|
763
|
+
element pre-warm resolves and the item cards can mount. The kernel has no
|
|
764
|
+
later loading signal, so the two modes currently emit the same sequence.
|
|
765
|
+
Default: `"progressive"`.
|
|
623
766
|
- `preload.enabled` — when `false`, `SectionItemsPane` short-circuits the
|
|
624
767
|
section-level element warmup pipeline (`warmupSectionElements`). Items
|
|
625
768
|
still mount and item-players register their own elements on demand. Use
|
|
@@ -631,10 +774,8 @@ runtime effect; nothing in this surface is decorative.
|
|
|
631
774
|
shape of opt-out can still override `runtime.player.loaderConfig.instrumentationProvider`.
|
|
632
775
|
Default: `true`.
|
|
633
776
|
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
host code that needs to mirror the same gate (e.g. when composing a custom
|
|
637
|
-
layout host) can call them directly.
|
|
777
|
+
`resolveSectionPlayerPolicies(policies)` returns the filled-in object, for
|
|
778
|
+
host code that needs the same gates.
|
|
638
779
|
|
|
639
780
|
### Navigation signals
|
|
640
781
|
|
|
@@ -643,20 +784,20 @@ layout host) can call them directly.
|
|
|
643
784
|
|
|
644
785
|
Runtime configuration is explicit:
|
|
645
786
|
|
|
646
|
-
- `runtime` owns runtime fields (`assessmentId`, `playerType`, `player`, `lazyInit`, `tools`, `accessibility`, `coordinator`, `isolation`, `env`, `
|
|
787
|
+
- `runtime` owns runtime fields (`assessmentId`, `playerType`, `player`, `lazyInit`, `tools`, `toolContextResolvers`, `accessibility`, `coordinator`, `createSectionController`, `isolation`, `env`, `contentLanguage` and the `on*` callbacks). `locale`, `nds-icons` and `tool-config-strictness` are attributes only.
|
|
647
788
|
- Tool placement is configured through `runtime.tools.placement.section`, `runtime.tools.placement.item`, and `runtime.tools.placement.passage`.
|
|
648
|
-
- Tool configuration validation is canonical in toolkit initialization (`pie-assessment-toolkit`), including toolbar overlays. Use `
|
|
789
|
+
- Tool configuration validation is canonical in toolkit initialization (`pie-assessment-toolkit`), including toolbar overlays. Use the `tool-config-strictness` attribute (`off` | `warn` | `error`) to control warning-only vs fail-fast behavior.
|
|
649
790
|
- TTS provider config must use `tools.providers.textToSpeech` (canonical). `tools.providers.tts` is rejected by validation.
|
|
650
|
-
- Host tool overrides
|
|
651
|
-
- `toolRegistry`
|
|
791
|
+
- Host tool overrides:
|
|
792
|
+
- `toolRegistry` replaces the default toolbar registry when provided. Build it with `createPackagedToolRegistry({ toolModuleLoaders: DEFAULT_TOOL_MODULE_LOADERS })` and register custom tools on it, since toolbars load each tool's element through the registry's loaders. A player that builds its own coordinator gives it this registry; a coordinator passed as `runtime.coordinator` keeps its own, which decides policy, so build that coordinator with the same registry
|
|
652
793
|
- host buttons are appended per toolbar scope via `sectionHostButtons`, `itemHostButtons`, `passageHostButtons`
|
|
653
794
|
|
|
654
|
-
Debug logging
|
|
795
|
+
Debug logging is page-wide. A layout's `debug` attribute writes `window.PIE_DEBUG`, the flag every PIE logger on the page reads, so the last host to set it decides for all of them:
|
|
655
796
|
|
|
656
797
|
- Enable: `<pie-section-player-splitpane debug="true">`
|
|
657
798
|
- Disable: `<pie-section-player-splitpane debug="false">` (or `debug="0"`)
|
|
658
799
|
|
|
659
|
-
|
|
800
|
+
Without a `debug` attribute a layout follows `window.PIE_DEBUG`, which a host can set directly.
|
|
660
801
|
|
|
661
802
|
See the progressive demo routes in `apps/section-demos/src/routes/(demos)` (for example `single-question/+page.svelte` and `session-hydrate-db/+page.svelte`) for end-to-end host integrations.
|
|
662
803
|
|
|
@@ -685,49 +826,138 @@ Structural composition changes (new/removed/reordered entities) may legitimately
|
|
|
685
826
|
|
|
686
827
|
## Custom layout authoring
|
|
687
828
|
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
<
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
829
|
+
A host builds its own section layout from `pie-section-player-kernel-host` and the
|
|
830
|
+
two panes. The kernel host runs the section: toolkit, section controller,
|
|
831
|
+
readiness, element pre-warm and the section toolbar. Its element children are the
|
|
832
|
+
layout, and the panes inside them render the section's items and passages. The
|
|
833
|
+
stock layouts are built from the same panes.
|
|
834
|
+
|
|
835
|
+
```html
|
|
836
|
+
<!doctype html>
|
|
837
|
+
<html lang="en">
|
|
838
|
+
<head>
|
|
839
|
+
<meta charset="utf-8" />
|
|
840
|
+
<style>
|
|
841
|
+
body { margin: 0; }
|
|
842
|
+
pie-section-player-kernel-host { display: block; height: 100vh; }
|
|
843
|
+
.columns { display: grid; grid-template-columns: 3fr 2fr; height: 100%; }
|
|
844
|
+
.column { min-height: 0; overflow: auto; }
|
|
845
|
+
</style>
|
|
846
|
+
<script type="module">
|
|
847
|
+
import "https://cdn.jsdelivr.net/npm/@pie-players/pie-section-player@x.y.z/dist/browser/pie-section-player.js";
|
|
848
|
+
|
|
849
|
+
const player = document.querySelector("pie-section-player-kernel-host");
|
|
850
|
+
player.addEventListener("pie-loading-complete", () => {
|
|
851
|
+
console.log("ready", player.getSnapshot().navigation);
|
|
852
|
+
});
|
|
853
|
+
player.runtime = { env: { mode: "gather", role: "student" } };
|
|
854
|
+
player.section = {
|
|
855
|
+
identifier: "water-cycle",
|
|
856
|
+
rubricBlocks: [
|
|
857
|
+
{
|
|
858
|
+
identifier: "passage-1",
|
|
859
|
+
class: "stimulus",
|
|
860
|
+
view: ["candidate"],
|
|
861
|
+
passage: {
|
|
862
|
+
id: "passage-1",
|
|
863
|
+
config: {
|
|
864
|
+
markup: "<p>Water evaporates, condenses into clouds and falls as rain.</p>",
|
|
865
|
+
elements: {},
|
|
866
|
+
models: [],
|
|
867
|
+
},
|
|
868
|
+
},
|
|
869
|
+
},
|
|
870
|
+
],
|
|
871
|
+
assessmentItemRefs: [
|
|
872
|
+
{
|
|
873
|
+
identifier: "item-1",
|
|
874
|
+
item: {
|
|
875
|
+
id: "item-1",
|
|
876
|
+
config: {
|
|
877
|
+
markup: "<p>Name the stage in which water vapour forms clouds.</p>",
|
|
878
|
+
elements: {},
|
|
879
|
+
models: [],
|
|
880
|
+
},
|
|
881
|
+
},
|
|
882
|
+
},
|
|
883
|
+
],
|
|
884
|
+
};
|
|
885
|
+
</script>
|
|
886
|
+
</head>
|
|
887
|
+
<body>
|
|
888
|
+
<pie-section-player-kernel-host section-id="water-cycle" attempt-id="attempt-1">
|
|
889
|
+
<div class="columns">
|
|
890
|
+
<div class="column"><pie-section-player-items-pane></pie-section-player-items-pane></div>
|
|
891
|
+
<div class="column"><pie-section-player-passages-pane></pie-section-player-passages-pane></div>
|
|
892
|
+
</div>
|
|
893
|
+
</pie-section-player-kernel-host>
|
|
894
|
+
</body>
|
|
895
|
+
</html>
|
|
724
896
|
```
|
|
725
897
|
|
|
898
|
+
The example loads the [browser build](../../docs/setup/cdn_usage.md#section-player-browser-build).
|
|
899
|
+
A bundled host imports `@pie-players/pie-section-player`, which defines the
|
|
900
|
+
kernel host and the panes too. An item with PIE elements names them in
|
|
901
|
+
`config.elements` and carries their `config.models`, as in any section. The
|
|
902
|
+
`/custom-layout` route of `apps/section-demos`
|
|
903
|
+
([source](../../apps/section-demos/src/routes/%28demos%29/custom-layout/+page.svelte))
|
|
904
|
+
builds the same two columns in Svelte.
|
|
905
|
+
|
|
906
|
+
### Kernel host
|
|
907
|
+
|
|
908
|
+
- **Inputs and host methods.** Those of the layout elements in
|
|
909
|
+
[Runtime Inputs](#runtime-inputs), without the layout dimensions
|
|
910
|
+
(`narrow-layout-breakpoint`, `content-max-width-*`, `split-pane-*`).
|
|
911
|
+
- **DOM.** The open shadow root holds the toolkit and the section toolbar around
|
|
912
|
+
one default slot; `show-toolbar` and `toolbar-position` place the toolbar around
|
|
913
|
+
the layout. The children, the panes and the content they render stay in light
|
|
914
|
+
DOM, where page styles and the content stylesheet reach them. The element has
|
|
915
|
+
no styles of its own, so the host gives it `display` and a height.
|
|
916
|
+
- **Stock body.** With no element children it renders its own layout, the
|
|
917
|
+
passages pane above the items pane, and places the passages pane only for a
|
|
918
|
+
section with passages. The stock body leaves when the first element child
|
|
919
|
+
arrives and returns when the last one leaves. Text and comment children do not
|
|
920
|
+
count, so markup whitespace and a framework's placeholder comments leave it in
|
|
921
|
+
place.
|
|
922
|
+
- **Navigation and state.** The host methods (`navigateNext`, `navigatePrevious`,
|
|
923
|
+
`navigateTo`, `getSnapshot`, `getSectionController`, `waitForSectionController`)
|
|
924
|
+
and the events (`pie-stage-change`, `pie-loading-complete`,
|
|
925
|
+
`composition-changed`, `session-changed`, `framework-error`, `toolkit-ready`)
|
|
926
|
+
are those of the stock layouts. `detail.sourceCe` on its `pie-stage-change`
|
|
927
|
+
and `pie-loading-complete` events reads `pie-section-player-kernel-host`.
|
|
928
|
+
|
|
929
|
+
### Panes
|
|
930
|
+
|
|
931
|
+
`<pie-section-player-items-pane>` renders the item cards of the current
|
|
932
|
+
composition, with their toolbars, and runs the element pre-warm;
|
|
933
|
+
`<pie-section-player-passages-pane>` renders the passage cards. A pane takes no
|
|
934
|
+
attributes or properties, and its pre-warm failures arrive as the section
|
|
935
|
+
player's `framework-error` and `element-preload-error` events. It reads the
|
|
936
|
+
section player it belongs to from a context the kernel publishes, so it renders
|
|
937
|
+
at any depth below the kernel host, and outside a section player it renders
|
|
938
|
+
nothing.
|
|
939
|
+
|
|
940
|
+
- **One pane of each kind renders**: the first connected. A second pane of a
|
|
941
|
+
kind renders nothing and takes over when the first disconnects; the player
|
|
942
|
+
reports the duplicate once in the console.
|
|
943
|
+
- **Readiness follows the rendering items pane.** `interactive` and
|
|
944
|
+
`pie-loading-complete` wait for its element pre-warm, and reports from any
|
|
945
|
+
other pane are ignored. A section with items and no items pane never reaches
|
|
946
|
+
either; the player reports it once in the console a task after
|
|
947
|
+
`section-ready`.
|
|
948
|
+
- **The passages pane is optional.** A section without passages needs none, and
|
|
949
|
+
readiness does not wait for it.
|
|
950
|
+
- **Scrolling belongs to the layout.** The items pane's scroll hint follows the
|
|
951
|
+
nearest ancestor with `overflow-y: auto` or `scroll`, so the layout gives each
|
|
952
|
+
pane's container that overflow and a bounded height. The stock layouts' pane backdrops and margins
|
|
953
|
+
stay with those layouts; the cards keep their tags and
|
|
954
|
+
[styling hooks](#card-header-styling-hooks).
|
|
955
|
+
|
|
726
956
|
### JS API example for advanced host policy
|
|
727
957
|
|
|
728
958
|
```ts
|
|
729
959
|
const host = document.querySelector("pie-section-player-splitpane") as any;
|
|
730
|
-
const controller = await host.waitForSectionController
|
|
960
|
+
const controller = await host.waitForSectionController(5000);
|
|
731
961
|
let sectionComplete = false;
|
|
732
962
|
|
|
733
963
|
const unsubscribe = controller?.subscribe?.((event: any) => {
|
|
@@ -737,7 +967,7 @@ const unsubscribe = controller?.subscribe?.((event: any) => {
|
|
|
737
967
|
});
|
|
738
968
|
|
|
739
969
|
function canAdvance() {
|
|
740
|
-
const nav = host.
|
|
970
|
+
const nav = host.getSnapshot?.()?.navigation;
|
|
741
971
|
return Boolean(nav?.canNext && sectionComplete);
|
|
742
972
|
}
|
|
743
973
|
```
|
|
@@ -758,7 +988,7 @@ const unsubscribeSection = coordinator.subscribeSectionLifecycleEvents({
|
|
|
758
988
|
});
|
|
759
989
|
```
|
|
760
990
|
|
|
761
|
-
Subscribe **after** the first `getOrCreateSectionController(...)` resolves (or after `toolkit-ready` once the section player has fully wired its controller — typically the safest anchor in host code is `toolkit-ready` followed by the first controller-resolve). Calling subscribe before
|
|
991
|
+
Subscribe **after** the first `getOrCreateSectionController(...)` resolves (or after `toolkit-ready` once the section player has fully wired its controller — typically the safest anchor in host code is `toolkit-ready` followed by the first controller-resolve). Calling subscribe before the first `getOrCreateSectionController(...)` call throws; a listener added while a section is starting binds when that section becomes active.
|
|
762
992
|
|
|
763
993
|
Use `subscribeSectionEvents(...)` only for advanced mixed filtering requirements.
|
|
764
994
|
|
|
@@ -810,52 +1040,41 @@ Section-player instrumentation is provider-agnostic and uses the shared
|
|
|
810
1040
|
- Toolkit telemetry forwarding uses the same provider path, so tool/backend
|
|
811
1041
|
operational events are visible alongside section events when toolkit is mounted.
|
|
812
1042
|
|
|
813
|
-
Canonical lifecycle stream (engine-routed, dispatched on the outer layout CE
|
|
1043
|
+
Canonical lifecycle stream (engine-routed, dispatched on the outer layout CE,
|
|
1044
|
+
bubbling and composed):
|
|
814
1045
|
|
|
815
1046
|
- `pie-stage-change` — single typed transition stream covering
|
|
816
1047
|
`composed` → `engine-ready` → `interactive` → `disposed`. Payload is a
|
|
817
|
-
`StageChangeDetail`.
|
|
818
|
-
|
|
819
|
-
|
|
1048
|
+
`StageChangeDetail`. A non-recoverable framework error before
|
|
1049
|
+
`interactive` emits the current stage `failed` and each stage it never
|
|
1050
|
+
reached `skipped`.
|
|
1051
|
+
- `pie-loading-complete` — fires once per cohort, when the section's element
|
|
1052
|
+
pre-warm resolves for the current composition and the item cards can mount
|
|
1053
|
+
(kernel-routed).
|
|
820
1054
|
- `framework-error` — canonical error event for any failure crossing the
|
|
821
|
-
framework boundary. Payload is a `FrameworkErrorModel`. The toolkit
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
Callback-prop mirrors with two-tier precedence (`runtime.<key>` wins over
|
|
834
|
-
the top-level prop):
|
|
835
|
-
|
|
836
|
-
- `onStageChange(detail)` — on every layout CE, `pie-section-player-base`,
|
|
837
|
-
and `pie-assessment-toolkit`.
|
|
838
|
-
- `onLoadingComplete(detail)` — on the kernel-backed layout CEs only
|
|
839
|
-
(split-pane / vertical / tabbed / kernel-host).
|
|
840
|
-
- `onFrameworkError(model)` — on every layout CE and
|
|
841
|
-
`pie-section-player-base`. Fires exactly once per error regardless of
|
|
842
|
-
wrapper depth (delivered through the package-internal
|
|
843
|
-
`FrameworkErrorBus`). The `framework-error` DOM event on the layout
|
|
844
|
-
CE host is also single-fire; consume either.
|
|
1055
|
+
framework boundary. Payload is a `FrameworkErrorModel`. The toolkit
|
|
1056
|
+
dispatches it once per error, bubbling and composed, so it reaches the
|
|
1057
|
+
layout CE and `document`; errors from a coordinator the host passes as
|
|
1058
|
+
`runtime.coordinator` arrive the same way.
|
|
1059
|
+
`tests/section-player-event-delivery.spec.ts` pins these counts.
|
|
1060
|
+
|
|
1061
|
+
Callbacks on `runtime`:
|
|
1062
|
+
|
|
1063
|
+
- `runtime.onStageChange(detail)` and `runtime.onLoadingComplete(detail)`.
|
|
1064
|
+
- `runtime.onFrameworkError(model)` fires once per error regardless of
|
|
1065
|
+
wrapper depth, like the `framework-error` DOM event; consume either.
|
|
845
1066
|
|
|
846
1067
|
Section-player owned instrumentation stream:
|
|
847
1068
|
|
|
848
1069
|
- `pie-section-stage-change`
|
|
849
1070
|
- `pie-section-loading-complete`
|
|
850
|
-
- `pie-section-session-changed`
|
|
851
|
-
- `pie-section-composition-changed`
|
|
852
1071
|
- `pie-section-framework-error`
|
|
1072
|
+
- `pie-section-element-preload-retry`
|
|
1073
|
+
- `pie-section-element-preload-error`
|
|
853
1074
|
|
|
854
1075
|
Build consumers against these canonical lifecycle events:
|
|
855
1076
|
|
|
856
|
-
- `readiness-change` → listen for `pie-stage-change`.
|
|
857
|
-
payload is also available via `selectReadiness()` /
|
|
858
|
-
`getSnapshot().readiness` on the layout CE.
|
|
1077
|
+
- `readiness-change` → listen for `pie-stage-change`.
|
|
859
1078
|
- `interaction-ready` → `pie-stage-change` filtered on
|
|
860
1079
|
`detail.stage === "interactive"`.
|
|
861
1080
|
- `ready` → `pie-loading-complete`.
|
|
@@ -880,7 +1099,7 @@ Section session data can be managed either through persistence hooks or directly
|
|
|
880
1099
|
|
|
881
1100
|
```ts
|
|
882
1101
|
const host = document.querySelector("pie-section-player-splitpane") as any;
|
|
883
|
-
const controller = await host.waitForSectionController
|
|
1102
|
+
const controller = await host.waitForSectionController(5000);
|
|
884
1103
|
|
|
885
1104
|
// Read current section session snapshot.
|
|
886
1105
|
const currentSession = controller?.getSession?.();
|
|
@@ -905,9 +1124,34 @@ await controller?.updateItemSession?.("q1", {
|
|
|
905
1124
|
});
|
|
906
1125
|
```
|
|
907
1126
|
|
|
908
|
-
The same controller snapshot is what the persistence strategy saves/loads
|
|
1127
|
+
The same controller snapshot is what the persistence strategy saves/loads, and
|
|
1128
|
+
what the layout's `session` property takes.
|
|
909
1129
|
When a controller is reused for the same `sectionId`/`attemptId`, `updateInput()` refreshes composition input while preserving in-memory section session data.
|
|
910
1130
|
|
|
1131
|
+
### One item as a section
|
|
1132
|
+
|
|
1133
|
+
`sectionFromItem` wraps one item config, in the shape `<pie-item-player config>`
|
|
1134
|
+
takes, and optionally its session, in the `section` and `session` the layouts
|
|
1135
|
+
take. It is exported from the package root and from
|
|
1136
|
+
`@pie-players/pie-section-player/item-section`, which defines no custom element
|
|
1137
|
+
and imports in Node.
|
|
1138
|
+
|
|
1139
|
+
```ts
|
|
1140
|
+
import { sectionFromItem } from "@pie-players/pie-section-player/item-section";
|
|
1141
|
+
|
|
1142
|
+
const { section, session } = sectionFromItem(itemConfig, { session: itemSession });
|
|
1143
|
+
player.setAttribute("section-id", section.identifier);
|
|
1144
|
+
player.section = section;
|
|
1145
|
+
player.session = session;
|
|
1146
|
+
```
|
|
1147
|
+
|
|
1148
|
+
The item ref's `identifier` and the item's `id` are the config's `id`, so every
|
|
1149
|
+
`itemId` the section reports is the id the host already holds. An advanced
|
|
1150
|
+
config's `passage` becomes the item's passage, and its `instructorResources` and
|
|
1151
|
+
`defaultExtraModels` stay on the item's config. The section carries no `baseId`
|
|
1152
|
+
or `version`; `options.sectionId` names the section, which defaults to the
|
|
1153
|
+
config's `id`.
|
|
1154
|
+
|
|
911
1155
|
### Commit at a section boundary
|
|
912
1156
|
|
|
913
1157
|
A delivery element coalesces its `session-changed` dispatch, so a response the
|
|
@@ -917,13 +1161,23 @@ controller commits pending element sessions before item navigation, before
|
|
|
917
1161
|
The player also commits when an item shell tears down and when the page goes
|
|
918
1162
|
hidden.
|
|
919
1163
|
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
1164
|
+
A committed response travels like any other. A raw element `session-changed`
|
|
1165
|
+
does not leave its `<pie-item-scope>`, which re-dispatches it as the normalized
|
|
1166
|
+
`item-session-changed` (`PIE_ITEM_SESSION_CHANGED_EVENT`); the toolkit then
|
|
1167
|
+
publishes the section's canonical `session-changed`. Both bubble through the
|
|
1168
|
+
layout element to `document`, and a listener on either receives each dispatch
|
|
1169
|
+
once.
|
|
925
1170
|
Host code persists from the controller's events or from its session snapshot.
|
|
926
1171
|
|
|
1172
|
+
Each of those events marks a commit with `sessionCommitReason`
|
|
1173
|
+
(`"teardown" | "navigate" | "page-hidden"`): `item-session-changed`, the
|
|
1174
|
+
toolkit's `session-changed`, and the controller's `item-session-data-changed`
|
|
1175
|
+
and `item-session-meta-changed`. A commit at a section swap or item navigation
|
|
1176
|
+
reports the item being left, which the host may already have moved past, so a
|
|
1177
|
+
handler that sets its current item or navigation state from these events leaves
|
|
1178
|
+
that state alone on a commit and persists the commit's session as usual. The
|
|
1179
|
+
controller's events also carry `sectionId`, the section the item belongs to.
|
|
1180
|
+
|
|
927
1181
|
Navigation inside a section keeps every item mounted, so nothing is discarded
|
|
928
1182
|
and the element's own debounce would complete on its own. The commit still runs
|
|
929
1183
|
there because the response belongs to the item being left: a host that persists
|
|
@@ -941,8 +1195,9 @@ pending response at those boundaries.
|
|
|
941
1195
|
## Content trust boundary
|
|
942
1196
|
|
|
943
1197
|
Section-player layouts embed `<pie-item-player>` elements for each item.
|
|
944
|
-
Item and passage markup is sanitized by default via DOMPurify; see
|
|
945
|
-
[pie-item-player README](
|
|
1198
|
+
Item and passage markup is sanitized by default via DOMPurify; see the
|
|
1199
|
+
[pie-item-player README](../item-player/README.md#content-trust-boundary)
|
|
1200
|
+
for the allow-list, the `trust-markup` opt-out and the `sanitizeMarkup`
|
|
946
1201
|
property. Hosts can forward those settings through the section-player
|
|
947
1202
|
`runtime.player` overrides — the runtime flattens these onto the embedded
|
|
948
1203
|
`<pie-item-player>` instance, so any field not recognized by the kernel is
|
|
@@ -966,21 +1221,12 @@ produced by a trusted pipeline.
|
|
|
966
1221
|
Published exports are intentionally minimal:
|
|
967
1222
|
|
|
968
1223
|
- `@pie-players/pie-section-player`
|
|
969
|
-
- `@pie-players/pie-section-player/
|
|
970
|
-
- `@pie-players/pie-section-player/components/section-player-
|
|
971
|
-
- `@pie-players/pie-section-player/components/section-player-tabbed-element`
|
|
972
|
-
- `@pie-players/pie-section-player/components/section-player-kernel-host-element`
|
|
973
|
-
- `@pie-players/pie-section-player/components/section-player-shell-element`
|
|
974
|
-
- `@pie-players/pie-section-player/components/section-player-item-card-element`
|
|
975
|
-
- `@pie-players/pie-section-player/components/section-player-passage-card-element`
|
|
976
|
-
- `@pie-players/pie-section-player/components/section-player-items-pane-element`
|
|
977
|
-
- `@pie-players/pie-section-player/components/section-player-passages-pane-element`
|
|
978
|
-
- `@pie-players/pie-section-player/contracts/layout-contract`
|
|
979
|
-
- `@pie-players/pie-section-player/contracts/public-events`
|
|
1224
|
+
- `@pie-players/pie-section-player/browser`, the self-contained browser build ([CDN usage](../../docs/setup/cdn_usage.md#section-player-browser-build))
|
|
1225
|
+
- `@pie-players/pie-section-player/components/section-player-splitpane-element`, which resolves to the package root
|
|
980
1226
|
- `@pie-players/pie-section-player/contracts/runtime-host-contract`
|
|
981
|
-
- `@pie-players/pie-section-player/contracts/layout-parity-metadata`
|
|
982
1227
|
- `@pie-players/pie-section-player/contracts/host-hooks`
|
|
983
1228
|
- `@pie-players/pie-section-player/policies`
|
|
1229
|
+
- `@pie-players/pie-section-player/item-section`
|
|
984
1230
|
|
|
985
1231
|
## Development
|
|
986
1232
|
|