@pie-players/pie-section-player 0.3.52 → 0.3.54

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
@@ -178,9 +178,14 @@ For theme compatibility with existing passage-label patterns, tabs also expose:
178
178
  - `data-pie-purpose="passage-label"` and alias class `passage-label`
179
179
  - `data-pie-purpose="item-label"` and alias class `item-label`
180
180
 
181
- Tab colors/spacing can be themed via CSS variables such as:
182
- `--pie-section-player-tab-color`, `--pie-section-player-tab-active-color`,
183
- `--pie-section-player-tab-indicator-color`, and `--pie-section-player-tab-spacing`.
181
+ Tab colors, spacing, and track geometry can be themed via CSS variables:
182
+ `--pie-section-player-tab-color`, `--pie-section-player-tab-background`,
183
+ `--pie-section-player-tab-active-color`,
184
+ `--pie-section-player-tab-active-background`,
185
+ `--pie-section-player-tab-gap`,
186
+ `--pie-section-player-tab-track-radius`,
187
+ `--pie-section-player-tab-track-padding`, and
188
+ `--pie-section-player-tab-padding-block`.
184
189
 
185
190
  ### Card header styling hooks
186
191
 
@@ -191,16 +196,23 @@ Passage and item cards share a common header row
191
196
  - Title and toolbar are centered vertically by default. There is no prop or
192
197
  attribute for this — hosts needing a non-standard alignment should override
193
198
  the selector in their own stylesheet.
199
+ - Card corners default to `8px`. Hosts/themes can override the card radius via
200
+ `--pie-section-player-card-radius`.
194
201
  - The header fill is transparent by default. Hosts/themes opt into a color
195
202
  via the `--pie-section-player-card-header-background` CSS variable; the
196
203
  framework does not ship a brand palette.
204
+ - When a header fill is provided, header top corners default just inside the
205
+ card radius. Hosts/themes can override them independently via
206
+ `--pie-section-player-card-header-radius`.
197
207
 
198
208
  Example (host CSS):
199
209
 
200
210
  ```css
201
211
  pie-section-player-passage-card,
202
212
  pie-section-player-item-card {
213
+ --pie-section-player-card-radius: 8px;
203
214
  --pie-section-player-card-header-background: #c9e5e6;
215
+ --pie-section-player-card-header-radius: 7px;
204
216
  }
205
217
  ```
206
218
 
@@ -240,6 +252,70 @@ host.hooks = {
240
252
 
241
253
  Advanced runtime configuration is supplied through the `runtime` object. Set player config, tools, accessibility, coordinator, env, and `createSectionController` on `runtime.<key>`.
242
254
 
255
+ ### Backend delivery for embedded items
256
+
257
+ Hosts can configure item-player backend delivery once at the section-player
258
+ runtime level. Section-player derives a concrete `backend` prop for each
259
+ embedded item player before it renders the item. This is intended for hosts such
260
+ as Quiz Engine that need server-processed PIE models and server scoring without
261
+ querying every nested `<pie-item-player>`.
262
+
263
+ ```ts
264
+ import type {
265
+ SectionPlayerRuntimeConfig,
266
+ } from "@pie-players/pie-section-player";
267
+
268
+ const runtime: SectionPlayerRuntimeConfig = {
269
+ playerType: "iife",
270
+ env: {
271
+ mode: "gather",
272
+ role: "student",
273
+ },
274
+ player: {
275
+ backend: {
276
+ delivery: {
277
+ enabled: true,
278
+ baseUrl: bffUrl,
279
+ assignmentId: playerSessionId,
280
+ endpoints: {
281
+ load: "/api/player/load",
282
+ saveSession: "/api/player/save",
283
+ model: "/api/player/model",
284
+ score: "/api/player/score",
285
+ },
286
+ autosave: { enabled: true, debounceMs: 250 },
287
+ },
288
+ },
289
+ },
290
+ };
291
+
292
+ sectionPlayer.runtime = runtime;
293
+ ```
294
+
295
+ When `runtime.player.backend.delivery` is enabled, section-player treats
296
+ `itemId` and `sessionId` as per-item delivery identity. It derives them from
297
+ `canonicalItemId || item.id` and the item session before forwarding `backend` to
298
+ each embedded item player. Static delivery fields such as `baseUrl`, `auth`,
299
+ `endpoints`, `assignmentId`, and `autosave` are preserved. Use `assignmentId`
300
+ for shared attempt/player identity.
301
+
302
+ `runtime.player.resolveBackend` is a section-player-reserved key. It is called
303
+ with `{ itemId, canonicalItemId, item, itemIndex, itemSession, sectionId, env,
304
+ baseBackend }` and is stripped before props reach `<pie-item-player>`. Use it
305
+ only when the backend needs custom per-item identity mapping. The resolver
306
+ receives cloned backend objects, so per-item identity changes do not mutate the
307
+ shared runtime configuration or leak across items.
308
+
309
+ Section-player only derives the concrete `backend` prop. It does not call
310
+ `loadFromBackend()` on nested item players. Embedded `<pie-item-player>` loads
311
+ automatically when its derived `backend.delivery` config has a load signature,
312
+ so every mounted item player issues one backend load for its own item. Passage
313
+ players do not receive item delivery backend config, but shared non-delivery
314
+ backend config is preserved.
315
+
316
+ This backend delivery config is separate from the element-loader backend used
317
+ for IIFE/ESM bundle preloading.
318
+
243
319
  ### Host-owned focus
244
320
 
245
321
  Section-player does not move focus on behalf of host-level affordances such
@@ -0,0 +1,32 @@
1
+ import { BackendConfig } from '@pie-players/pie-item-player';
2
+ import { PlayerOverrides, RuntimeConfig } from '@pie-players/pie-assessment-toolkit/runtime/internal';
3
+ import { ItemEntity } from '@pie-players/pie-players-shared/types';
4
+ export type SectionPlayerBackendResolverContext = {
5
+ itemId: string;
6
+ canonicalItemId: string;
7
+ item: ItemEntity;
8
+ itemIndex: number;
9
+ itemSession?: Record<string, unknown>;
10
+ sectionId?: string;
11
+ env: Record<string, unknown>;
12
+ baseBackend: BackendConfig;
13
+ };
14
+ export type SectionPlayerBackendResolver = (context: SectionPlayerBackendResolverContext, baseBackend: BackendConfig) => BackendConfig | null | undefined;
15
+ export type SectionPlayerRuntimePlayerConfig = Omit<PlayerOverrides, "backend" | "resolveBackend"> & {
16
+ backend?: BackendConfig | null;
17
+ resolveBackend?: SectionPlayerBackendResolver;
18
+ };
19
+ export type SectionPlayerRuntimeConfig = Omit<RuntimeConfig, "player"> & {
20
+ player?: SectionPlayerRuntimePlayerConfig | null;
21
+ };
22
+ export type ResolveItemPlayerBackendPropsArgs = {
23
+ resolvedPlayerProps: Record<string, unknown>;
24
+ item: ItemEntity;
25
+ canonicalItemId: string;
26
+ itemSession?: Record<string, unknown>;
27
+ itemIndex?: number;
28
+ sectionId?: string;
29
+ env: Record<string, unknown>;
30
+ };
31
+ export declare function resolveItemPlayerPropsWithBackend(args: ResolveItemPlayerBackendPropsArgs): Record<string, unknown>;
32
+ export declare function stripItemDeliveryBackendProps(resolvedPlayerProps: Record<string, unknown>): Record<string, unknown>;
@@ -22,6 +22,13 @@ export declare function resolvePlayerRuntime(args: {
22
22
  [x: string]: unknown;
23
23
  };
24
24
  loaderConfig?: import('@pie-players/pie-players-shared').LoaderConfig;
25
+ hosted: boolean;
26
+ } | {
27
+ loaderOptions: {
28
+ [x: string]: unknown;
29
+ };
30
+ loaderConfig?: import('@pie-players/pie-players-shared').LoaderConfig;
31
+ hosted?: undefined;
25
32
  };
26
33
  resolvedPlayerEnv: Record<string, unknown>;
27
34
  strategy: import('@pie-players/pie-players-shared').ItemPlayerStrategy;
@@ -55,6 +62,13 @@ export declare function resolveSectionPlayerRuntimeState(args: RuntimeInputs): {
55
62
  [x: string]: unknown;
56
63
  };
57
64
  loaderConfig?: import('@pie-players/pie-players-shared').LoaderConfig;
65
+ hosted: boolean;
66
+ } | {
67
+ loaderOptions: {
68
+ [x: string]: unknown;
69
+ };
70
+ loaderConfig?: import('@pie-players/pie-players-shared').LoaderConfig;
71
+ hosted?: undefined;
58
72
  };
59
73
  resolvedPlayerEnv: Record<string, unknown>;
60
74
  strategy: import('@pie-players/pie-players-shared').ItemPlayerStrategy;
@@ -25,6 +25,7 @@ export declare function getItemPlayerParams(args: {
25
25
  resolvedPlayerAttributes: Record<string, string>;
26
26
  resolvedPlayerProps: Record<string, unknown>;
27
27
  playerStrategy: string;
28
+ itemIndex?: number;
28
29
  }): PlayerElementParams;
29
30
  export declare function getCanonicalItemId(args: {
30
31
  compositionModel: SectionCompositionModel;
@@ -7,3 +7,4 @@ export type { ReadinessPolicyAdapter, SectionPlayerPolicies, SectionPlayerReadin
7
7
  export { DEFAULT_SECTION_PLAYER_POLICIES, isPreloadEnabled, isTelemetryEnabled, } from './policies/index.js';
8
8
  export type { SectionPlayerCardTitleContext, SectionPlayerCardTitleFormatter, SectionPlayerItemTitleContext, SectionPlayerPassageTitleContext, } from './contracts/card-title-formatters.js';
9
9
  export type { SectionPlayerHostHooks } from './contracts/host-hooks.js';
10
+ export type { SectionPlayerBackendResolver, SectionPlayerBackendResolverContext, SectionPlayerRuntimeConfig, SectionPlayerRuntimePlayerConfig, } from './components/shared/section-player-backend-delivery.js';