@pie-players/pie-tool-sign-language 0.3.50

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 ADDED
@@ -0,0 +1,83 @@
1
+ # @pie-players/pie-tool-sign-language
2
+
3
+ The sign-language accommodation for PIE assessment players: a signed translation
4
+ of an item, docked beside its content.
5
+
6
+ This package is also the worked example of a capability contributed entirely from
7
+ outside the player. It is authored against
8
+ `@pie-players/pie-assessment-toolkit/tools/internal` — the same entry point the
9
+ packaged registrations use — and `@pie-players/pie-section-player` reaches it only
10
+ through `ToolRegistry.getToolsBySurface("content-media")`. No package in the player
11
+ names signing, the `signLanguage` support id, the `sign-language` catalog type or
12
+ this package.
13
+
14
+ ## Opting in
15
+
16
+ ```ts
17
+ import { signLanguageRegistration } from "@pie-players/pie-tool-sign-language";
18
+
19
+ registry.register(signLanguageRegistration);
20
+ ```
21
+
22
+ Importing the package registers the `pie-tool-sign-language` element, so there is
23
+ nothing else to wire and no module-loader entry to add.
24
+
25
+ Signing is deliberately absent from `createPackagedToolRegistry` and
26
+ `DEFAULT_TOOL_MODULE_LOADERS`. It is an accommodation with an authored-content
27
+ dependency: a default that granted it would hand the accommodation to every
28
+ learner whose item happened to carry a card.
29
+
30
+ ## Availability
31
+
32
+ Two independent halves, both required, neither implying the other.
33
+
34
+ **Eligibility** — policy granted `signLanguage`. Signing is an accommodation, so
35
+ silence means no. The host asks `decideFeaturePolicy` and never consults tool
36
+ placement: `activation: "region"` means there is no button to press, so a
37
+ `tools.placement` entry naming this capability is reported as unplaceable rather
38
+ than silently doing nothing.
39
+
40
+ **Content** — the item carries a matching `sign-language` catalog card. QTI
41
+ approximates AfA's DRD in-band: the presence of the card *is* the resource
42
+ declaration. This half is `requiresAuthoredContent.resolve`, and it is why a
43
+ learner with the accommodation still sees nothing on the vast majority of items.
44
+
45
+ A signed alternate reaches an item one way only: as a catalog card, authored or
46
+ written by an importer. There is no path that lifts a signing video out of item
47
+ markup at render time — one was implemented and removed, because it had no
48
+ producer and failed in the wrong direction, leaving the video in visible content
49
+ for every learner when the markup could not be parsed.
50
+
51
+ ## No cross-sign-language substitution
52
+
53
+ ASL, BSL and LSF are not interchangeable. The catalog resolver's last fallback
54
+ rung matches any card of the requested type regardless of language, which helps
55
+ for spoken audio and harms here: handing an ASL learner a BSL recording is worse
56
+ than handing them nothing. `resolveSignLanguageAlternate` therefore accepts a
57
+ card reached by that rung only when its language matches, or when the card
58
+ asserts no language at all.
59
+
60
+ ## The element
61
+
62
+ `<pie-tool-sign-language>` — open shadow root, mounted by the registration's
63
+ `renderSurface`, never authored directly. Props are `media` (a resolved
64
+ alternate) and `ttsService`; signing playback and read-aloud pause each other, and
65
+ the action the learner just took wins.
66
+
67
+ Sizing is driven by the recording's own frame shape, because signing needs height
68
+ for hands and face. Host overrides:
69
+
70
+ | Custom property | Default |
71
+ | --- | --- |
72
+ | `--pie-section-player-item-media-aspect-ratio` | `3 / 4` |
73
+ | `--pie-section-player-item-media-min-height` | `220px` |
74
+ | `--pie-section-player-item-media-max-height` | `60vh` |
75
+
76
+ The region's share of the card width, the drag-to-resize handle and the stacking
77
+ breakpoint belong to the host: that is the card's layout, not the capability's.
78
+
79
+ ## Related
80
+
81
+ - [`docs/prds/sign-language-asl-support.md`](../../docs/prds/sign-language-asl-support.md)
82
+ - [`docs/TOOL_REGISTRY.md`](../assessment-toolkit/docs/TOOL_REGISTRY.md) — host
83
+ surfaces and content dependencies
@@ -0,0 +1,5 @@
1
+ export { CONTENT_MEDIA_SURFACE, SIGN_LANGUAGE_ELEMENT_TAG, signLanguageRegistration, } from './src/sign-language-registration.js';
2
+ export type { SignLanguageMedia } from './src/sign-language-cards.js';
3
+ export { AMERICAN_SIGN_LANGUAGE, describeSignLanguage, isSignLanguageCard, matchesRequestedSignLanguage, resolveSignLanguageMedia, SIGN_LANGUAGE_CATALOG_TYPE, } from './src/sign-language-cards.js';
4
+ export type { ResolvedSignLanguageAlternate, SignLanguageCatalogRef, SignLanguageLookupArgs, } from './src/sign-language-content.js';
5
+ export { collectSignLanguageCatalogRefs, resolveRequestedSignLanguage, resolveSignLanguageAlternate, resolveSignLanguageContent, SIGN_LANGUAGE_FEATURE_ID, } from './src/sign-language-content.js';
@@ -0,0 +1,52 @@
1
+ import { CatalogCard, CatalogCardPayload, MediaFragmentRange, MediaSource } from '@pie-players/pie-players-shared/types';
2
+ /** Catalog type token for signed alternates. Matches QTI 3's `support` value. */
3
+ export declare const SIGN_LANGUAGE_CATALOG_TYPE = "sign-language";
4
+ /** ISO 639-3 code for American Sign Language, and QTI 3's `xml:lang` value. */
5
+ export declare const AMERICAN_SIGN_LANGUAGE = "ase";
6
+ export declare function describeSignLanguage(signLang?: string): string;
7
+ /**
8
+ * A validated signed alternate, flattened for rendering.
9
+ *
10
+ * `signLang` is optional because a card need not assert a language. Callers
11
+ * decide what to do with an unknown one; see `matchesRequestedSignLanguage`.
12
+ */
13
+ export interface SignLanguageMedia {
14
+ signLang?: string;
15
+ sources: MediaSource[];
16
+ poster?: string;
17
+ label?: string;
18
+ fragment?: MediaFragmentRange;
19
+ }
20
+ type SignLanguageCardLike = {
21
+ language?: string;
22
+ content?: string;
23
+ payload?: CatalogCardPayload;
24
+ };
25
+ /**
26
+ * Validate a `sign-language` card into something renderable, or `null`.
27
+ *
28
+ * Returns `null` — meaning "this card is absent" — when the payload yields no
29
+ * usable source. Never returns a partially-valid result that would render an
30
+ * empty player.
31
+ *
32
+ * A payload that carries sources but no `signLang` falls back to the card's
33
+ * `language`, and then to unlabelled. Language *matching* is a separate
34
+ * decision (see `matchesRequestedSignLanguage`) so the strict
35
+ * no-cross-sign-language rule lives in exactly one place.
36
+ */
37
+ export declare function resolveSignLanguageMedia(card: SignLanguageCardLike | null | undefined): SignLanguageMedia | null;
38
+ /**
39
+ * Whether a resolved signed alternate may be shown for a requested sign
40
+ * language.
41
+ *
42
+ * Deliberately strict: there is no cross-sign-language fallback. ASL, BSL and
43
+ * LSF are not interchangeable, so showing a different sign language than the
44
+ * one requested would hand a learner a language they may not follow — worse
45
+ * than showing nothing. A card that asserts *no* language is accepted, because it
46
+ * cannot be shown to be a mismatch — only a positive claim of another language
47
+ * is refused.
48
+ */
49
+ export declare function matchesRequestedSignLanguage(media: SignLanguageMedia, requestedSignLang: string): boolean;
50
+ /** Whether a catalog card is a sign-language card at all. */
51
+ export declare function isSignLanguageCard(card: CatalogCard): boolean;
52
+ export {};
@@ -0,0 +1,73 @@
1
+ import { CatalogOwnerContext, AccessibilityCatalogResolverApi, ToolContentDependencyContext } from '@pie-players/pie-assessment-toolkit';
2
+ import { ItemEntity } from '@pie-players/pie-players-shared/types';
3
+ import { SignLanguageMedia } from './sign-language-cards.js';
4
+ /** QTI 3.0 / AfA support id gating signed alternates. */
5
+ export declare const SIGN_LANGUAGE_FEATURE_ID = "signLanguage";
6
+ /** A catalog on this item that carries at least one sign-language card. */
7
+ export interface SignLanguageCatalogRef {
8
+ catalogId: string;
9
+ /** Set when the catalog is owned by one model rather than the item root. */
10
+ modelId?: string;
11
+ }
12
+ export interface ResolvedSignLanguageAlternate extends SignLanguageMedia {
13
+ catalogId: string;
14
+ }
15
+ /**
16
+ * Collect the catalog identifiers on an item that carry signing cards.
17
+ *
18
+ * The region resolves through the catalog resolver, but the resolver is keyed by
19
+ * identifier within an owner scope — something has to say *which* identifiers
20
+ * this item put in play, and whether each belongs to the item or to one model.
21
+ * That is the same walk the runtime does when it registers an item's catalogs,
22
+ * so it is borrowed rather than repeated: a ref can only name a scope
23
+ * registration actually files under. Only the "does this catalog carry signing"
24
+ * filter is ours.
25
+ *
26
+ * The owner identity here is a placeholder: the assessment and section ids are
27
+ * not known at extraction time and are supplied by the caller at lookup time
28
+ * (see `resolveSignLanguageAlternate`). Nothing but `modelId` is read from the
29
+ * walk's contexts.
30
+ */
31
+ export declare function collectSignLanguageCatalogRefs(item: ItemEntity | null | undefined): SignLanguageCatalogRef[];
32
+ export interface SignLanguageLookupArgs {
33
+ resolver: AccessibilityCatalogResolverApi;
34
+ refs: SignLanguageCatalogRef[];
35
+ /** Owner context for the item, without `modelId` — added per ref. */
36
+ ownerContext: CatalogOwnerContext;
37
+ /** Sign language the learner is entitled to, ISO 639-3. */
38
+ requestedSignLang?: string;
39
+ }
40
+ /**
41
+ * Resolve the signed alternate to show for an item, or `null`.
42
+ *
43
+ * Priority, language fallback and owner scoping are the resolver's job and are
44
+ * not re-implemented here. What *is* enforced here is the one deliberate
45
+ * departure from the resolver's default behaviour: **no cross-sign-language
46
+ * substitution.** The resolver's last fallback rung matches any card of the
47
+ * requested type regardless of language, which for spoken content is helpful
48
+ * and for signing is not — handing an ASL learner a BSL recording is worse than
49
+ * handing them nothing. So a card the resolver returns by that rung is accepted
50
+ * only if its language actually matches, or if the card asserts no language at
51
+ * all.
52
+ *
53
+ * MVP takes the first resolvable card: sample content is one recording per item.
54
+ * The refs stay per-node capable for when choice-level docking lands.
55
+ */
56
+ export declare function resolveSignLanguageAlternate(args: SignLanguageLookupArgs): ResolvedSignLanguageAlternate | null;
57
+ /**
58
+ * Which sign language the learner is entitled to.
59
+ *
60
+ * Read from the feature's policy parameters (`toolParameters` / `toolConfigs`),
61
+ * never inferred from the item's content language — a Spanish item's signed
62
+ * alternate is LSM, not ASL.
63
+ */
64
+ export declare function resolveRequestedSignLanguage(parameters: unknown): string | undefined;
65
+ /**
66
+ * The registration's `requiresAuthoredContent` implementation: the whole
67
+ * content half behind the one call the host makes.
68
+ *
69
+ * The host supplies the item, the resolver and the owner scope, and learns only
70
+ * whether there is something to render. It never sees a catalog type, a card
71
+ * shape or a sign-language code.
72
+ */
73
+ export declare function resolveSignLanguageContent(context: ToolContentDependencyContext): ResolvedSignLanguageAlternate | null;
@@ -0,0 +1,12 @@
1
+ import { ToolRegistration } from '@pie-players/pie-assessment-toolkit/tools/internal';
2
+ /**
3
+ * Host surface this capability docks into: media beside a card's content.
4
+ *
5
+ * Item cards and passage cards open the same surface, so declaring it once
6
+ * reaches both. A signed alternate is authored against a content node, and a
7
+ * passage owns content nodes as an item does.
8
+ */
9
+ export declare const CONTENT_MEDIA_SURFACE = "content-media";
10
+ /** Element tag this package registers. A host may substitute its own. */
11
+ export declare const SIGN_LANGUAGE_ELEMENT_TAG = "pie-tool-sign-language";
12
+ export declare const signLanguageRegistration: ToolRegistration;