@pie-players/pie-players-shared 0.3.75 → 1.0.0-beta.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.
- package/README.md +88 -77
- package/dist/components/vendor/nds/README.md +4 -5
- package/dist/config/profile.d.ts +1 -1
- package/dist/config/profile.js +1 -1
- package/dist/i18n/index.d.ts +1 -1
- package/dist/i18n/index.js +1 -1
- package/dist/i18n/language-tags.d.ts +9 -1
- package/dist/i18n/language-tags.js +11 -1
- package/dist/i18n/messages/en-US.d.ts +33 -5
- package/dist/i18n/messages/en-US.js +33 -5
- package/dist/i18n/messages/nl-NL.d.ts +33 -5
- package/dist/i18n/messages/nl-NL.js +33 -5
- package/dist/i18n/provider.d.ts +14 -7
- package/dist/i18n/provider.js +26 -29
- package/dist/index.js +0 -1
- package/dist/instrumentation/providers/BaseInstrumentationProvider.js +0 -14
- package/dist/loader-config.d.ts +0 -2
- package/dist/loader-config.js +0 -2
- package/dist/loaders/element-loader.js +13 -6
- package/dist/loaders/esm-adapter.js +48 -37
- package/dist/loaders/iife-adapter.d.ts +3 -3
- package/dist/loaders/iife-adapter.js +36 -35
- package/dist/media/index.d.ts +4 -6
- package/dist/media/index.js +6 -8
- package/dist/object/index.d.ts +8 -3
- package/dist/object/index.js +8 -6
- package/dist/pie/asset-handler.d.ts +0 -17
- package/dist/pie/asset-handler.js +1 -1
- package/dist/pie/authoring.js +5 -7
- package/dist/pie/elements-rendered.d.ts +0 -2
- package/dist/pie/elements-rendered.js +1 -1
- package/dist/pie/initialization.d.ts +13 -14
- package/dist/pie/initialization.js +61 -75
- package/dist/pie/item-session-contract.js +7 -9
- package/dist/pie/resource-monitor.d.ts +34 -32
- package/dist/pie/resource-monitor.js +152 -231
- package/dist/pie/stages.d.ts +4 -3
- package/dist/pie/stages.js +4 -3
- package/dist/pie/updates.js +5 -4
- package/dist/pie/utils.d.ts +0 -2
- package/dist/pie/utils.js +0 -2
- package/dist/security/sanitize-item-markup.d.ts +4 -4
- package/dist/security/sanitize-item-markup.js +4 -4
- package/dist/security/sanitize-svg-icon.js +2 -2
- package/dist/security/wrap-overwide-images.d.ts +1 -1
- package/dist/security/wrap-overwide-images.js +1 -1
- package/dist/timed-media/media-element-source.js +1 -2
- package/dist/types/index.d.ts +62 -52
- package/dist/types/index.js +2 -2
- package/dist/ui/attribute-coercion.d.ts +5 -0
- package/dist/ui/attribute-coercion.js +6 -4
- package/dist/ui/content-styles.d.ts +6 -10
- package/dist/ui/content-styles.js +8 -13
- package/dist/ui/first-focusable.d.ts +0 -1
- package/dist/ui/first-focusable.js +0 -1
- package/dist/ui/focus-trap.js +2 -3
- package/dist/ui/scope-css.d.ts +23 -26
- package/dist/ui/scope-css.js +23 -26
- package/package.json +3 -2
package/dist/pie/stages.d.ts
CHANGED
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
* A cohort (one section and attempt) moves through `composed`,
|
|
5
5
|
* `engine-ready`, `interactive` and `disposed`, in that order. The section
|
|
6
6
|
* runtime engine in `@pie-players/pie-assessment-toolkit` is the only emitter;
|
|
7
|
-
* it dispatches the event on the layout element. `pie-loading-complete`
|
|
8
|
-
*
|
|
9
|
-
* "strict"` only
|
|
7
|
+
* it dispatches the event on the layout element. `pie-loading-complete` is
|
|
8
|
+
* not a stage; it fires once per cohort when the section controller is ready
|
|
9
|
+
* and the element pre-warm has resolved. `readiness.mode = "strict"` only
|
|
10
|
+
* delays `interactive`.
|
|
10
11
|
*
|
|
11
12
|
* `status` is `entered`, or `failed` for the stage a non-recoverable
|
|
12
13
|
* framework error stopped the chain at, with `skipped` for each later stage
|
package/dist/pie/stages.js
CHANGED
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
* A cohort (one section and attempt) moves through `composed`,
|
|
5
5
|
* `engine-ready`, `interactive` and `disposed`, in that order. The section
|
|
6
6
|
* runtime engine in `@pie-players/pie-assessment-toolkit` is the only emitter;
|
|
7
|
-
* it dispatches the event on the layout element. `pie-loading-complete`
|
|
8
|
-
*
|
|
9
|
-
* "strict"` only
|
|
7
|
+
* it dispatches the event on the layout element. `pie-loading-complete` is
|
|
8
|
+
* not a stage; it fires once per cohort when the section controller is ready
|
|
9
|
+
* and the element pre-warm has resolved. `readiness.mode = "strict"` only
|
|
10
|
+
* delays `interactive`.
|
|
10
11
|
*
|
|
11
12
|
* `status` is `entered`, or `failed` for the stage a non-recoverable
|
|
12
13
|
* framework error stopped the chain at, with `skipped` for each later stage
|
package/dist/pie/updates.js
CHANGED
|
@@ -8,7 +8,6 @@ import { createPieLogger, isGlobalDebugEnabled } from "./logger.js";
|
|
|
8
8
|
import { findPieController } from "./scoring.js";
|
|
9
9
|
import { defaultPieElementOptions } from "./types.js";
|
|
10
10
|
import { findOrAddSession } from "./utils.js";
|
|
11
|
-
// Create module-level logger (respects global debug flag - pass function for dynamic checking)
|
|
12
11
|
const logger = createPieLogger("pie-updates", () => isGlobalDebugEnabled());
|
|
13
12
|
const describeControllerShape = (controller) => {
|
|
14
13
|
if (!controller)
|
|
@@ -67,8 +66,10 @@ const trackRemoval = (element) => {
|
|
|
67
66
|
return () => wasConnected && !element.isConnected;
|
|
68
67
|
};
|
|
69
68
|
/**
|
|
70
|
-
*
|
|
71
|
-
*
|
|
69
|
+
* Runs the controller's `model()` and assigns the result to the element, with
|
|
70
|
+
* the authored model's `id` and `element` as defaults, together with the
|
|
71
|
+
* session the controller may have written to. Assigns nothing once the element
|
|
72
|
+
* was removed.
|
|
72
73
|
*/
|
|
73
74
|
const applyControllerToElement = async (element, model, elementSession, controller, env, logPrefix, wasRemoved, onElementSessionUpdate) => {
|
|
74
75
|
logger.debug(`${logPrefix} Using controller, env:`, env);
|
|
@@ -118,7 +119,7 @@ const applyControllerToElement = async (element, model, elementSession, controll
|
|
|
118
119
|
}
|
|
119
120
|
catch (err) {
|
|
120
121
|
logger.error(`${logPrefix} ❌ Controller error:`, err);
|
|
121
|
-
throw err; //
|
|
122
|
+
throw err; // The caller reports it and falls back to the authored model.
|
|
122
123
|
}
|
|
123
124
|
};
|
|
124
125
|
const resolveAndValidateUpdateOptions = (opts) => {
|
package/dist/pie/utils.d.ts
CHANGED
|
@@ -60,8 +60,6 @@ export declare const getPackageWithoutVersion: (packages: string) => string;
|
|
|
60
60
|
/**
|
|
61
61
|
* Find or add a session entry for a given element
|
|
62
62
|
*
|
|
63
|
-
* TODO: kinda gnarly, copied from player project
|
|
64
|
-
*
|
|
65
63
|
* @param data - Session data array
|
|
66
64
|
* @param id - Model/element ID
|
|
67
65
|
* @param element - Element tag name (optional)
|
package/dist/pie/utils.js
CHANGED
|
@@ -103,8 +103,6 @@ export const getPackageWithoutVersion = (packages) => packages
|
|
|
103
103
|
/**
|
|
104
104
|
* Find or add a session entry for a given element
|
|
105
105
|
*
|
|
106
|
-
* TODO: kinda gnarly, copied from player project
|
|
107
|
-
*
|
|
108
106
|
* @param data - Session data array
|
|
109
107
|
* @param id - Model/element ID
|
|
110
108
|
* @param element - Element tag name (optional)
|
|
@@ -31,8 +31,8 @@ export interface SanitizeItemMarkupOptions {
|
|
|
31
31
|
* Sanitize raw item/passage markup before it is injected into the DOM.
|
|
32
32
|
*
|
|
33
33
|
* - Strips `<script>`, event-handler attributes, unknown protocols and
|
|
34
|
-
*
|
|
35
|
-
* `form`, `meta`, `link`).
|
|
34
|
+
* the other tags in `SANITIZER_FORBIDDEN_TAGS` (`iframe`, `object`, `embed`,
|
|
35
|
+
* `base`, `form`, `meta`, `link`, `style`, `foreignObject`).
|
|
36
36
|
* - Preserves PIE custom elements (`pie-*`) and any extra tags listed in
|
|
37
37
|
* `allowedCustomElements`.
|
|
38
38
|
* - Marks elements that carry an authored color, as `markAuthoredColors`
|
|
@@ -46,8 +46,8 @@ export interface SanitizeItemMarkupOptions {
|
|
|
46
46
|
export declare function sanitizeItemMarkup(markup: string, options?: SanitizeItemMarkupOptions): string;
|
|
47
47
|
/**
|
|
48
48
|
* Build the default `ItemMarkupSanitizer` used by the players. The returned
|
|
49
|
-
* function
|
|
50
|
-
*
|
|
49
|
+
* function captures the options once; each call returns a new function, so a
|
|
50
|
+
* caller that compares sanitizers by identity keeps the one it built.
|
|
51
51
|
*/
|
|
52
52
|
export declare function createDefaultItemMarkupSanitizer(options?: SanitizeItemMarkupOptions): ItemMarkupSanitizer;
|
|
53
53
|
/**
|
|
@@ -102,8 +102,8 @@ function resolvePurifier() {
|
|
|
102
102
|
* Sanitize raw item/passage markup before it is injected into the DOM.
|
|
103
103
|
*
|
|
104
104
|
* - Strips `<script>`, event-handler attributes, unknown protocols and
|
|
105
|
-
*
|
|
106
|
-
* `form`, `meta`, `link`).
|
|
105
|
+
* the other tags in `SANITIZER_FORBIDDEN_TAGS` (`iframe`, `object`, `embed`,
|
|
106
|
+
* `base`, `form`, `meta`, `link`, `style`, `foreignObject`).
|
|
107
107
|
* - Preserves PIE custom elements (`pie-*`) and any extra tags listed in
|
|
108
108
|
* `allowedCustomElements`.
|
|
109
109
|
* - Marks elements that carry an authored color, as `markAuthoredColors`
|
|
@@ -167,8 +167,8 @@ export function sanitizeItemMarkup(markup, options = {}) {
|
|
|
167
167
|
}
|
|
168
168
|
/**
|
|
169
169
|
* Build the default `ItemMarkupSanitizer` used by the players. The returned
|
|
170
|
-
* function
|
|
171
|
-
*
|
|
170
|
+
* function captures the options once; each call returns a new function, so a
|
|
171
|
+
* caller that compares sanitizers by identity keeps the one it built.
|
|
172
172
|
*/
|
|
173
173
|
export function createDefaultItemMarkupSanitizer(options = {}) {
|
|
174
174
|
const { allowedCustomElements, wrapOverwideContent } = options;
|
|
@@ -51,8 +51,8 @@ export function sanitizeSvgIcon(icon) {
|
|
|
51
51
|
});
|
|
52
52
|
const str = typeof result === "string" ? result : String(result ?? "");
|
|
53
53
|
if (stringCache.size >= STRING_CACHE_MAX) {
|
|
54
|
-
//
|
|
55
|
-
// a small fixed set per assessment so this
|
|
54
|
+
// Evict the oldest-inserted half when full; a hit does not refresh an entry.
|
|
55
|
+
// Tool icons are a small fixed set per assessment, so this rarely runs.
|
|
56
56
|
const keys = [...stringCache.keys()];
|
|
57
57
|
for (let i = 0; i < keys.length / 2; i += 1) {
|
|
58
58
|
stringCache.delete(keys[i]);
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* they never appeared in the authored markup string.
|
|
25
25
|
*
|
|
26
26
|
* The wrapping itself lives in `./wrap-overwide.js`, shared with the table
|
|
27
|
-
* wrapper: only the
|
|
27
|
+
* wrapper: only the spec below differs.
|
|
28
28
|
*/
|
|
29
29
|
import { type WrapOverwideOptions } from "./wrap-overwide.js";
|
|
30
30
|
export type WrapOverwideImagesInElementOptions = WrapOverwideOptions;
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* they never appeared in the authored markup string.
|
|
25
25
|
*
|
|
26
26
|
* The wrapping itself lives in `./wrap-overwide.js`, shared with the table
|
|
27
|
-
* wrapper: only the
|
|
27
|
+
* wrapper: only the spec below differs.
|
|
28
28
|
*/
|
|
29
29
|
import { isOverwideWrapMutation, wrapOverwideInElement, wrapOverwideMarkup, } from "./wrap-overwide.js";
|
|
30
30
|
function buildAriaLabel(image) {
|
|
@@ -116,6 +116,5 @@ export function createMediaElementTimeSource(element, options = {}) {
|
|
|
116
116
|
export function findMediaElement(root) {
|
|
117
117
|
if (!root)
|
|
118
118
|
return null;
|
|
119
|
-
|
|
120
|
-
return found ?? null;
|
|
119
|
+
return root.querySelector("video, audio");
|
|
121
120
|
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
2
|
+
* The PIE content and assessment model the players share: item, passage and
|
|
3
|
+
* section configs, the QTI-aligned assessment structure, session snapshots,
|
|
4
|
+
* accessibility catalogs and media references, `Env`, the element controller
|
|
5
|
+
* contract and authoring asset events.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* The `*Entity` shapes mirror content-store records and may be shallower than
|
|
8
|
+
* them. The module depends on nothing beyond this package's own type modules,
|
|
9
|
+
* so front-end and server code can both import it.
|
|
9
10
|
*/
|
|
10
11
|
import type { FormativeDeliveryPolicy, FormativeItemPolicy, FormativeSectionSlice } from "../formative/types.js";
|
|
11
12
|
import type { TimedMediaSectionData, TimedMediaSectionSessionSlice } from "../timed-media/types.js";
|
|
@@ -55,10 +56,12 @@ export interface ConfigEntity {
|
|
|
55
56
|
markup: string;
|
|
56
57
|
elements: ConfigElements;
|
|
57
58
|
models: PieModel[];
|
|
59
|
+
/** Configure settings for authoring mode. */
|
|
58
60
|
configuration?: Record<string, any>;
|
|
59
61
|
/**
|
|
60
62
|
* QTI 3.0: Extracted accessibility catalogs from embedded SSML.
|
|
61
|
-
*
|
|
63
|
+
* Written by SSMLExtractor when a host's preprocessing runs it over content
|
|
64
|
+
* holding <speak> tags; the players register what this carries.
|
|
62
65
|
*/
|
|
63
66
|
extractedCatalogs?: AccessibilityCatalog[];
|
|
64
67
|
[key: string]: any;
|
|
@@ -77,12 +80,9 @@ export interface PassageEntity extends VersionEntity, ConfigContainerEntity, Sea
|
|
|
77
80
|
export interface ItemEntity extends VersionEntity, ConfigContainerEntity, SearchMetaDataEntity {
|
|
78
81
|
name?: string;
|
|
79
82
|
/**
|
|
80
|
-
* `null` as well as absent, because importers write it
|
|
81
|
-
* `undefined`, so an item transformed from another format carries an
|
|
82
|
-
* `passage: null` for "no passage"
|
|
83
|
-
* null, so it expected it while the type denied it. Excluding null
|
|
84
|
-
* only meant a host feeding real importer output through a typed path had to
|
|
85
|
-
* cast it away.
|
|
83
|
+
* `null` as well as absent, because importers write it: JSON has no
|
|
84
|
+
* `undefined`, so an item transformed from another format carries an
|
|
85
|
+
* explicit `passage: null` for "no passage", and the runtime tests for it.
|
|
86
86
|
*/
|
|
87
87
|
passage?: string | PassageEntity | null;
|
|
88
88
|
/** QTI/APIP-style accessibility catalogs owned by the item root. */
|
|
@@ -241,11 +241,9 @@ export interface TestPart {
|
|
|
241
241
|
* The host-facing persistence snapshot for one section, returned by
|
|
242
242
|
* `SectionControllerHandle.getSession()` and accepted by `applySession()`.
|
|
243
243
|
*
|
|
244
|
-
* Canonical here
|
|
245
|
-
*
|
|
246
|
-
*
|
|
247
|
-
* The delivery slices it carries are defined in this package too, which is what
|
|
248
|
-
* previously forced them to reference this shape in prose instead of types.
|
|
244
|
+
* Canonical here, beside `AssessmentSection`: both entry paths need it, and the
|
|
245
|
+
* toolkit complements a player and sits beneath both of them. The delivery
|
|
246
|
+
* slices it carries live in this package too, so they reference it as a type.
|
|
249
247
|
*/
|
|
250
248
|
export interface SectionControllerSessionState {
|
|
251
249
|
currentItemIndex?: number;
|
|
@@ -371,7 +369,7 @@ export interface MediaFragmentRange {
|
|
|
371
369
|
* inside `qti-card-entry` — multiple sources, MIME types, poster, and an
|
|
372
370
|
* optional time range.
|
|
373
371
|
*
|
|
374
|
-
*
|
|
372
|
+
* It carries no `kind` discriminant: the card's `catalog` field is QTI's
|
|
375
373
|
* `qti-card@support` and is the only discriminator. Restating it here would
|
|
376
374
|
* create a second source of truth that can disagree with the first.
|
|
377
375
|
*/
|
|
@@ -382,15 +380,12 @@ export interface SignLanguageCardPayload {
|
|
|
382
380
|
* signed alternate is LSM, not ASL, so this must never be inferred from the
|
|
383
381
|
* item or assessment content language.
|
|
384
382
|
*
|
|
385
|
-
* Optional
|
|
386
|
-
*
|
|
387
|
-
*
|
|
388
|
-
*
|
|
389
|
-
*
|
|
390
|
-
*
|
|
391
|
-
* where the two genuinely differ, which is a card tagged with the item's
|
|
392
|
-
* content language (`language: "en-US"`, `signLang: "ase"`) so that resolution
|
|
393
|
-
* reaches it by the default-language rung.
|
|
383
|
+
* Optional: when absent, the card's `language` stands in, so author it only
|
|
384
|
+
* where the two differ. The sign-language tool reads every signing card in
|
|
385
|
+
* the owner's scope and selects on this value: a card in the requested sign
|
|
386
|
+
* language wins, a card naming no language is the fallback, and a card in
|
|
387
|
+
* another sign language is never shown. It also names the language in the
|
|
388
|
+
* region's accessible label.
|
|
394
389
|
*/
|
|
395
390
|
signLang?: string;
|
|
396
391
|
media: MediaAssetRef;
|
|
@@ -401,8 +396,7 @@ export interface SignLanguageCardPayload {
|
|
|
401
396
|
*
|
|
402
397
|
* QTI 3 treats recorded audio and synthesized speech as the *same* support:
|
|
403
398
|
* both are `spoken`, and a card holds recorded audio through `qti-file-href`
|
|
404
|
-
* plus a MIME type.
|
|
405
|
-
* existing one can take.
|
|
399
|
+
* plus a MIME type. A recording is the other form that accommodation takes.
|
|
406
400
|
*
|
|
407
401
|
* A node commonly carries both this and a `content` card in the same language —
|
|
408
402
|
* APIP's pattern, which QTI's migration guidance keeps, because the script is
|
|
@@ -435,15 +429,13 @@ export type CatalogCardPayload = SignLanguageCardPayload | SpokenAudioCardPayloa
|
|
|
435
429
|
* one of `content` or `payload`.
|
|
436
430
|
*
|
|
437
431
|
* One generic `payload` slot, not a field per accommodation. This is the shape
|
|
438
|
-
* `pie-elements-ng`
|
|
439
|
-
*
|
|
440
|
-
*
|
|
441
|
-
*
|
|
442
|
-
*
|
|
443
|
-
*
|
|
444
|
-
*
|
|
445
|
-
* its signing video and simultaneously reported that the item had no signed
|
|
446
|
-
* alternate. Both producers now emit `payload` and the alias is gone.
|
|
432
|
+
* `pie-elements-ng` and the PIE API service's Learnosity importer restate
|
|
433
|
+
* structurally; all three read the same authored JSON and none of them takes a
|
|
434
|
+
* package dependency on the others, so keeping the declarations identical is
|
|
435
|
+
* the only thing holding interop together; a `signLanguage` input alias, folded
|
|
436
|
+
* in on the resolution path but not the enumeration path, once had an imported
|
|
437
|
+
* card render its signing video while reporting no signed alternate. Both
|
|
438
|
+
* producers now emit `payload`.
|
|
447
439
|
*/
|
|
448
440
|
export interface CatalogCard {
|
|
449
441
|
catalog: string;
|
|
@@ -517,18 +509,36 @@ export interface AssessmentSettings {
|
|
|
517
509
|
toolOverrides?: Record<string, boolean>;
|
|
518
510
|
};
|
|
519
511
|
/**
|
|
520
|
-
* Parameters by tool id, handed to
|
|
521
|
-
*
|
|
522
|
-
* the toolkit's `tools.providers`.
|
|
512
|
+
* Parameters by tool id, handed to the tool wherever policy shows it; an
|
|
513
|
+
* item's `toolParameters` entry wins on that item's own toolbar. Provider
|
|
514
|
+
* configuration belongs in the toolkit's `tools.providers`.
|
|
523
515
|
*/
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
516
|
+
toolParameters?: ToolParameters;
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* Parameter shapes by tool id. A tool outside the stock set may add its own by
|
|
520
|
+
* declaration merging, with a type literal as the value.
|
|
521
|
+
*
|
|
522
|
+
* The values come from authored content, so a tool still checks what it reads.
|
|
523
|
+
*/
|
|
524
|
+
export interface ToolParameterMap {
|
|
525
|
+
calculator: {
|
|
526
|
+
type?: "basic" | "scientific" | "graphing";
|
|
527
|
+
};
|
|
528
|
+
answerEliminator: {
|
|
529
|
+
strategy?: "strikethrough" | "mask";
|
|
530
|
+
};
|
|
531
|
+
signLanguage: {
|
|
532
|
+
signLang?: string;
|
|
527
533
|
};
|
|
528
534
|
}
|
|
529
|
-
/**
|
|
530
|
-
export type
|
|
531
|
-
|
|
535
|
+
/** The parameter shape of tool `K`: its {@link ToolParameterMap} entry, else open. */
|
|
536
|
+
export type ToolParametersFor<K extends string> = K extends keyof ToolParameterMap ? ToolParameterMap[K] : Record<string, unknown>;
|
|
537
|
+
/** Parameters by tool id: typed for the ids {@link ToolParameterMap} names. */
|
|
538
|
+
export type ToolParameters = {
|
|
539
|
+
[K in keyof ToolParameterMap]?: ToolParameterMap[K];
|
|
540
|
+
} & {
|
|
541
|
+
[toolId: string]: Record<string, unknown> | undefined;
|
|
532
542
|
};
|
|
533
543
|
/**
|
|
534
544
|
* Item-level settings for tool requirements.
|
|
@@ -537,8 +547,8 @@ export type AssessmentCalculatorConfig = {
|
|
|
537
547
|
export interface ItemSettings {
|
|
538
548
|
requiredTools?: string[];
|
|
539
549
|
restrictedTools?: string[];
|
|
540
|
-
/** Parameters by tool id; outranks the assessment's `
|
|
541
|
-
toolParameters?:
|
|
550
|
+
/** Parameters by tool id; outranks the assessment's `toolParameters` entry. */
|
|
551
|
+
toolParameters?: ToolParameters;
|
|
542
552
|
}
|
|
543
553
|
export type PlayerMode = "gather" | "view" | "evaluate" | "author";
|
|
544
554
|
export type PlayerRole = "student" | "instructor";
|
|
@@ -636,8 +646,8 @@ export interface AdvancedItemConfig {
|
|
|
636
646
|
}
|
|
637
647
|
export type ItemConfig = PieContent | AdvancedItemConfig;
|
|
638
648
|
/**
|
|
639
|
-
*
|
|
640
|
-
*
|
|
649
|
+
* Appended to an element's tag name to register the bundle's editor component
|
|
650
|
+
* as a custom element of its own when PIE bundles load.
|
|
641
651
|
*/
|
|
642
652
|
export declare const editorPostFix = "-pie-editor--";
|
|
643
653
|
export type ModelUpdatedDetail = {
|
package/dist/types/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* Appended to an element's tag name to register the bundle's editor component
|
|
3
|
+
* as a custom element of its own when PIE bundles load.
|
|
4
4
|
*/
|
|
5
5
|
export const editorPostFix = "-pie-editor--";
|
|
6
6
|
export class ModelUpdatedEvent extends CustomEvent {
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads a boolean-like prop or attribute value. Nullish or blank reads as
|
|
3
|
+
* `defaultValue`; `false`, `0`, `off` and `no` (any case) read as false; any
|
|
4
|
+
* other value reads as true.
|
|
5
|
+
*/
|
|
1
6
|
export declare function coerceBooleanLike(value: boolean | string | null | undefined, defaultValue?: boolean): boolean;
|
|
2
7
|
/**
|
|
3
8
|
* Reads a boolean attribute value: present is true and absent is false, as in
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads a boolean-like prop or attribute value. Nullish or blank reads as
|
|
3
|
+
* `defaultValue`; `false`, `0`, `off` and `no` (any case) read as false; any
|
|
4
|
+
* other value reads as true.
|
|
5
|
+
*/
|
|
1
6
|
export function coerceBooleanLike(value, defaultValue = false) {
|
|
2
7
|
if (typeof value === "boolean") {
|
|
3
8
|
return value;
|
|
@@ -12,10 +17,7 @@ export function coerceBooleanLike(value, defaultValue = false) {
|
|
|
12
17
|
if (["false", "0", "off", "no"].includes(normalizedValue)) {
|
|
13
18
|
return false;
|
|
14
19
|
}
|
|
15
|
-
|
|
16
|
-
return true;
|
|
17
|
-
}
|
|
18
|
-
return Boolean(normalizedValue);
|
|
20
|
+
return true;
|
|
19
21
|
}
|
|
20
22
|
/**
|
|
21
23
|
* Reads a boolean attribute value: present is true and absent is false, as in
|
|
@@ -9,11 +9,9 @@
|
|
|
9
9
|
* light DOM, so those rules have to exist as a document-level stylesheet —
|
|
10
10
|
* there is no shadow root to scope them to.
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* hand days later. Players install the stylesheet themselves instead, which
|
|
16
|
-
* keeps the host contract at "import the player".
|
|
12
|
+
* Players install that stylesheet themselves, which keeps the host contract at
|
|
13
|
+
* "import the player"; a host-side import was unenforced and failed silently,
|
|
14
|
+
* as an unstyled passage.
|
|
17
15
|
*
|
|
18
16
|
* The CSS text is passed in rather than imported here: this package builds with
|
|
19
17
|
* plain `tsc`, so it cannot inline a stylesheet. Bundler-built player packages
|
|
@@ -58,11 +56,9 @@ export declare function contentStylesPresent(): boolean;
|
|
|
58
56
|
* hand — first in the entry, before app CSS — so an app rule and a content rule
|
|
59
57
|
* of equal specificity resolve in the host's favour, exactly as before.
|
|
60
58
|
*
|
|
61
|
-
* A cascade layer
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
* `.numbered-paragraph { margin-left: 36px }`. That trades a visible missing
|
|
65
|
-
* stylesheet for a subtler override bug, so ordinary specificity wins instead.
|
|
59
|
+
* A cascade layer would invert that: unlayered author declarations beat *all*
|
|
60
|
+
* layered ones regardless of specificity, so a host reset as broad as
|
|
61
|
+
* `p { margin: 0 }` would outrank `.numbered-paragraph { margin-left: 36px }`.
|
|
66
62
|
*
|
|
67
63
|
* @param cssText Contents of `@pie-players/pie-theme/components.css`.
|
|
68
64
|
* @param source Package installing the styles, for diagnostics.
|
|
@@ -9,11 +9,9 @@
|
|
|
9
9
|
* light DOM, so those rules have to exist as a document-level stylesheet —
|
|
10
10
|
* there is no shadow root to scope them to.
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* hand days later. Players install the stylesheet themselves instead, which
|
|
16
|
-
* keeps the host contract at "import the player".
|
|
12
|
+
* Players install that stylesheet themselves, which keeps the host contract at
|
|
13
|
+
* "import the player"; a host-side import was unenforced and failed silently,
|
|
14
|
+
* as an unstyled passage.
|
|
17
15
|
*
|
|
18
16
|
* The CSS text is passed in rather than imported here: this package builds with
|
|
19
17
|
* plain `tsc`, so it cannot inline a stylesheet. Bundler-built player packages
|
|
@@ -48,9 +46,8 @@ const declaresContentStylesSentinel = (rule) => {
|
|
|
48
46
|
// Grouping rules hold no declarations of their own, so the sentinel sits one
|
|
49
47
|
// or more levels down. A host that confines its copy — `@scope
|
|
50
48
|
// (.item-content) { … }`, `@layer pie-content { … }` — presents exactly one
|
|
51
|
-
// top-level rule with an empty `.style`,
|
|
52
|
-
// as "no copy here".
|
|
53
|
-
// configuration this module most needs to recognise.
|
|
49
|
+
// top-level rule with an empty `.style`, which a top-level-only scan reads
|
|
50
|
+
// as "no copy here".
|
|
54
51
|
const nested = rule.cssRules;
|
|
55
52
|
if (!nested)
|
|
56
53
|
return false;
|
|
@@ -115,11 +112,9 @@ export function contentStylesPresent() {
|
|
|
115
112
|
* hand — first in the entry, before app CSS — so an app rule and a content rule
|
|
116
113
|
* of equal specificity resolve in the host's favour, exactly as before.
|
|
117
114
|
*
|
|
118
|
-
* A cascade layer
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
* `.numbered-paragraph { margin-left: 36px }`. That trades a visible missing
|
|
122
|
-
* stylesheet for a subtler override bug, so ordinary specificity wins instead.
|
|
115
|
+
* A cascade layer would invert that: unlayered author declarations beat *all*
|
|
116
|
+
* layered ones regardless of specificity, so a host reset as broad as
|
|
117
|
+
* `p { margin: 0 }` would outrank `.numbered-paragraph { margin-left: 36px }`.
|
|
123
118
|
*
|
|
124
119
|
* @param cssText Contents of `@pie-players/pie-theme/components.css`.
|
|
125
120
|
* @param source Package installing the styles, for diagnostics.
|
package/dist/ui/focus-trap.js
CHANGED
|
@@ -57,9 +57,8 @@ export function createFocusTrap(container, options = {}) {
|
|
|
57
57
|
container.focus?.();
|
|
58
58
|
return;
|
|
59
59
|
}
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
: document);
|
|
60
|
+
const rootNode = container.getRootNode();
|
|
61
|
+
const current = getDeepActiveElement(rootNode instanceof ShadowRoot ? rootNode : document);
|
|
63
62
|
const currentIndex = focusable.indexOf(current || focusable[0]);
|
|
64
63
|
if (event.shiftKey) {
|
|
65
64
|
if (currentIndex <= 0) {
|
package/dist/ui/scope-css.d.ts
CHANGED
|
@@ -4,37 +4,34 @@
|
|
|
4
4
|
* external-style-urls="...">` or `itemConfig.resources.stylesheets[*].url`
|
|
5
5
|
* styles that player's subtree instead of the whole host document.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
7
|
+
* Walks the stylesheet brace-by-brace. Block at-rules that hold rules
|
|
8
|
+
* (`@media`, `@supports`, `@container`, `@layer`, `@scope`) keep their prelude
|
|
9
|
+
* and have their inner rules scoped, every other at-rule passes through, and a
|
|
10
|
+
* leading `:root`, `html` or `body` is replaced by the scope, since
|
|
11
|
+
* `.scope :root` can never match: `:root` is `<html>`, which is no descendant
|
|
12
|
+
* of the player. A regex prefixer fails on exactly these cases: it turned
|
|
13
|
+
* `@media screen { … }` into the invalid `.scope @media screen { … }`, which the
|
|
14
|
+
* browser drops with every rule inside, and corrupted `@font-face`,
|
|
15
|
+
* `@keyframes` and `:root` the same way.
|
|
15
16
|
*
|
|
16
|
-
* The QTI player's `scopeCssRules` (`pie-qti` -
|
|
17
|
-
* `packages/item-player/src/components/utils/stylesheetRender.ts`) is
|
|
18
|
-
* drop-in
|
|
19
|
-
*
|
|
20
|
-
* at
|
|
21
|
-
* rules are hoisted and applied unconditionally — a mobile-only rule then
|
|
22
|
-
* applies at every viewport width, which is a subtler failure than dropping it.
|
|
17
|
+
* The `:root` handling follows the QTI player's `scopeCssRules` (`pie-qti` -
|
|
18
|
+
* `packages/item-player/src/components/utils/stylesheetRender.ts`), which is no
|
|
19
|
+
* drop-in: it excludes `@` from its selector pattern without understanding
|
|
20
|
+
* at-rules, so `@media` and `@supports` lose their condition and their rules
|
|
21
|
+
* apply at every viewport width.
|
|
23
22
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* runs in the delivery path, and scoping needs to know about rule boundaries
|
|
28
|
-
* only — not about property grammar.
|
|
23
|
+
* No CSS parser: `@pie-players/pie-item-player` ships with two workspace
|
|
24
|
+
* dependencies, this runs in the delivery path, and scoping needs rule
|
|
25
|
+
* boundaries only.
|
|
29
26
|
*
|
|
30
|
-
* Known limits
|
|
27
|
+
* Known limits:
|
|
31
28
|
*
|
|
32
|
-
* - `@import` is passed through untouched
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
29
|
+
* - `@import` is passed through untouched. It pulls in an unscoped stylesheet,
|
|
30
|
+
* so it defeats scoping, but blocking it is a security policy decision and
|
|
31
|
+
* not this function's job. Callers gate stylesheet URLs with
|
|
32
|
+
* `validateExternalStyleUrl` before fetching.
|
|
36
33
|
* - Declaration blocks are emitted verbatim, so `url(...)` references are left
|
|
37
|
-
* as authored and resolve against the stylesheet's own URL
|
|
34
|
+
* as authored and resolve against the stylesheet's own URL.
|
|
38
35
|
* - A style rule's block is never rewritten, which is also what native CSS
|
|
39
36
|
* nesting needs: nested selectors are relative to a parent that has already
|
|
40
37
|
* been scoped.
|