@intellectif/lk-react 14.1.0 → 15.0.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/CHANGELOG.md +32 -0
- package/README.md +5 -2
- package/dist/{WrittenResponse-rRpOr9W1.d.cts → WrittenResponse-BPbhERgk.d.cts} +1 -1
- package/dist/{WrittenResponse-DrzI89Wg.d.ts → WrittenResponse-ZAxLR_AU.d.ts} +1 -1
- package/dist/{chunk-4Y5TELVU.cjs → chunk-26GQO5I2.cjs} +12 -12
- package/dist/{chunk-4Y5TELVU.cjs.map → chunk-26GQO5I2.cjs.map} +1 -1
- package/dist/chunk-2HAEQDHQ.js +2330 -0
- package/dist/chunk-2HAEQDHQ.js.map +1 -0
- package/dist/{chunk-NJAF34GN.js → chunk-33BQNWAQ.js} +5 -5
- package/dist/{chunk-NJAF34GN.js.map → chunk-33BQNWAQ.js.map} +1 -1
- package/dist/{chunk-N536RUCZ.cjs → chunk-4H3JTX74.cjs} +13 -13
- package/dist/{chunk-N536RUCZ.cjs.map → chunk-4H3JTX74.cjs.map} +1 -1
- package/dist/{chunk-AWQ53DON.js → chunk-52GXJNQ3.js} +83 -2
- package/dist/chunk-52GXJNQ3.js.map +1 -0
- package/dist/{chunk-DPEY7DSE.cjs → chunk-53YOZOGN.cjs} +5 -5
- package/dist/{chunk-DPEY7DSE.cjs.map → chunk-53YOZOGN.cjs.map} +1 -1
- package/dist/{chunk-U432HTUW.js → chunk-AF72QUBI.js} +5 -5
- package/dist/{chunk-U432HTUW.js.map → chunk-AF72QUBI.js.map} +1 -1
- package/dist/{chunk-IDYZ2FA2.js → chunk-CE6OGJE6.js} +5 -5
- package/dist/{chunk-IDYZ2FA2.js.map → chunk-CE6OGJE6.js.map} +1 -1
- package/dist/{chunk-CTW3G3EH.cjs → chunk-DP3DM7FR.cjs} +6 -6
- package/dist/{chunk-CTW3G3EH.cjs.map → chunk-DP3DM7FR.cjs.map} +1 -1
- package/dist/{chunk-MZITNWZ2.cjs → chunk-DQ3VVU5T.cjs} +24 -24
- package/dist/{chunk-MZITNWZ2.cjs.map → chunk-DQ3VVU5T.cjs.map} +1 -1
- package/dist/{chunk-PSUKWVKU.cjs → chunk-EKBEKDWO.cjs} +13 -13
- package/dist/{chunk-PSUKWVKU.cjs.map → chunk-EKBEKDWO.cjs.map} +1 -1
- package/dist/{chunk-RXS455MR.js → chunk-EVBYEWHO.js} +3 -2
- package/dist/chunk-EVBYEWHO.js.map +1 -0
- package/dist/{chunk-UMDWVMB5.cjs → chunk-FKGUKFC7.cjs} +5 -5
- package/dist/{chunk-UMDWVMB5.cjs.map → chunk-FKGUKFC7.cjs.map} +1 -1
- package/dist/{chunk-RCPW6HVY.js → chunk-H6I2JDNW.js} +10 -10
- package/dist/{chunk-RCPW6HVY.js.map → chunk-H6I2JDNW.js.map} +1 -1
- package/dist/{chunk-DB4DLHN6.js → chunk-HA3VRF6E.js} +3 -3
- package/dist/{chunk-DB4DLHN6.js.map → chunk-HA3VRF6E.js.map} +1 -1
- package/dist/{chunk-UDZWYHDV.js → chunk-I2QGW4GD.js} +11 -11
- package/dist/{chunk-UDZWYHDV.js.map → chunk-I2QGW4GD.js.map} +1 -1
- package/dist/{chunk-5CP2Z6IS.js → chunk-IE5ZNCWN.js} +5 -5
- package/dist/{chunk-5CP2Z6IS.js.map → chunk-IE5ZNCWN.js.map} +1 -1
- package/dist/{chunk-JG4DWAUJ.cjs → chunk-L7NE7PR4.cjs} +13 -13
- package/dist/{chunk-JG4DWAUJ.cjs.map → chunk-L7NE7PR4.cjs.map} +1 -1
- package/dist/{chunk-5JFMXBH7.js → chunk-QEB6O6GU.js} +6 -6
- package/dist/{chunk-5JFMXBH7.js.map → chunk-QEB6O6GU.js.map} +1 -1
- package/dist/{chunk-TUVEJLOT.js → chunk-QM4AV6EG.js} +4 -4
- package/dist/{chunk-TUVEJLOT.js.map → chunk-QM4AV6EG.js.map} +1 -1
- package/dist/{chunk-UDQS5INQ.js → chunk-RT5FTHUU.js} +5 -5
- package/dist/{chunk-UDQS5INQ.js.map → chunk-RT5FTHUU.js.map} +1 -1
- package/dist/chunk-SRD4KVAP.cjs +2332 -0
- package/dist/chunk-SRD4KVAP.cjs.map +1 -0
- package/dist/{chunk-5JCTJFQU.cjs → chunk-UAYWLYFW.cjs} +18 -18
- package/dist/{chunk-5JCTJFQU.cjs.map → chunk-UAYWLYFW.cjs.map} +1 -1
- package/dist/{chunk-D4DQFTA7.cjs → chunk-UCKA22ZJ.cjs} +3 -2
- package/dist/chunk-UCKA22ZJ.cjs.map +1 -0
- package/dist/{chunk-YM64MS4G.cjs → chunk-WKOV25NP.cjs} +8 -8
- package/dist/{chunk-YM64MS4G.cjs.map → chunk-WKOV25NP.cjs.map} +1 -1
- package/dist/{chunk-WC4OD3EE.cjs → chunk-XMJE34FY.cjs} +13 -13
- package/dist/{chunk-WC4OD3EE.cjs.map → chunk-XMJE34FY.cjs.map} +1 -1
- package/dist/{chunk-AS2QGND5.js → chunk-YWQH35VO.js} +4 -4
- package/dist/{chunk-AS2QGND5.js.map → chunk-YWQH35VO.js.map} +1 -1
- package/dist/{chunk-VSFHJ7FB.cjs → chunk-Z6TVOAO5.cjs} +83 -2
- package/dist/chunk-Z6TVOAO5.cjs.map +1 -0
- package/dist/{chunk-KIO6QXGT.cjs → chunk-ZH5WT2IE.cjs} +25 -25
- package/dist/{chunk-KIO6QXGT.cjs.map → chunk-ZH5WT2IE.cjs.map} +1 -1
- package/dist/{chunk-B4BCEQNO.js → chunk-ZJMTHPHY.js} +3 -3
- package/dist/{chunk-B4BCEQNO.js.map → chunk-ZJMTHPHY.js.map} +1 -1
- package/dist/components/ActivityPreview.cjs +12 -12
- package/dist/components/ActivityPreview.d.cts +2 -2
- package/dist/components/ActivityPreview.d.ts +2 -2
- package/dist/components/ActivityPreview.js +11 -11
- package/dist/components/ActivitySequence.cjs +13 -13
- package/dist/components/ActivitySequence.d.cts +2 -2
- package/dist/components/ActivitySequence.d.ts +2 -2
- package/dist/components/ActivitySequence.js +12 -12
- package/dist/components/Dictation.cjs +5 -5
- package/dist/components/Dictation.d.cts +1 -1
- package/dist/components/Dictation.d.ts +1 -1
- package/dist/components/Dictation.js +4 -4
- package/dist/components/FillInTheBlanks.cjs +5 -5
- package/dist/components/FillInTheBlanks.d.cts +1 -1
- package/dist/components/FillInTheBlanks.d.ts +1 -1
- package/dist/components/FillInTheBlanks.js +4 -4
- package/dist/components/GapSelect.cjs +5 -5
- package/dist/components/GapSelect.d.cts +1 -1
- package/dist/components/GapSelect.d.ts +1 -1
- package/dist/components/GapSelect.js +4 -4
- package/dist/components/InteractiveVideo.cjs +26 -0
- package/dist/components/InteractiveVideo.cjs.map +1 -0
- package/dist/components/InteractiveVideo.d.cts +77 -0
- package/dist/components/InteractiveVideo.d.ts +77 -0
- package/dist/components/InteractiveVideo.js +17 -0
- package/dist/components/InteractiveVideo.js.map +1 -0
- package/dist/components/MultipleChoice.cjs +5 -5
- package/dist/components/MultipleChoice.d.cts +1 -1
- package/dist/components/MultipleChoice.d.ts +1 -1
- package/dist/components/MultipleChoice.js +4 -4
- package/dist/components/PronunciationFeedback.cjs +4 -4
- package/dist/components/PronunciationFeedback.d.cts +1 -1
- package/dist/components/PronunciationFeedback.d.ts +1 -1
- package/dist/components/PronunciationFeedback.js +3 -3
- package/dist/components/ReadAloud.cjs +6 -6
- package/dist/components/ReadAloud.d.cts +2 -2
- package/dist/components/ReadAloud.d.ts +2 -2
- package/dist/components/ReadAloud.js +5 -5
- package/dist/components/StimulusPanel.cjs +4 -4
- package/dist/components/StimulusPanel.d.cts +1 -1
- package/dist/components/StimulusPanel.d.ts +1 -1
- package/dist/components/StimulusPanel.js +3 -3
- package/dist/components/WrittenResponse.cjs +5 -5
- package/dist/components/WrittenResponse.d.cts +3 -3
- package/dist/components/WrittenResponse.d.ts +3 -3
- package/dist/components/WrittenResponse.js +4 -4
- package/dist/i18n/LkIntlProvider.cjs +7 -7
- package/dist/i18n/LkIntlProvider.d.cts +2 -2
- package/dist/i18n/LkIntlProvider.d.ts +2 -2
- package/dist/i18n/LkIntlProvider.js +1 -1
- package/dist/index.cjs +44 -39
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +15 -14
- package/dist/index.js.map +1 -1
- package/dist/{strings-wjAF2ONm.d.cts → strings-5588Q4Te.d.cts} +102 -1
- package/dist/{strings-l8Wv1Xax.d.ts → strings-D0IWcsUm.d.ts} +102 -1
- package/dist/theme/ThemeProvider.cjs +6 -6
- package/dist/theme/ThemeProvider.js +1 -1
- package/dist/theme/defaults.css +2 -0
- package/dist/theme/skin.css +1348 -0
- package/package.json +13 -3
- package/dist/chunk-AWQ53DON.js.map +0 -1
- package/dist/chunk-D4DQFTA7.cjs.map +0 -1
- package/dist/chunk-RXS455MR.js.map +0 -1
- package/dist/chunk-VSFHJ7FB.cjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/ActivityPreview/ActivityPreview.tsx"],"names":["useLkStrings","useMemo","validateDraft","evaluate","slotMediaKey","jsx","Fragment","ActivityErrorBoundary","MultipleChoice","FillInTheBlanks","GapSelect","WrittenResponse","Dictation","ReadAloud"],"mappings":"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","file":"chunk-5JCTJFQU.cjs","sourcesContent":["'use client';\n\nimport {\n type ActivityType,\n type DraftNotComplete,\n evaluate,\n type ItemOutcome,\n type LearnerResponse,\n slotMediaKey,\n type ThemeTokens,\n validateDraft,\n} from '@intellectif/lk-core';\nimport { type ReactNode, useMemo } from 'react';\nimport { useLkStrings } from '../../i18n/LkIntlProvider.js';\nimport type { LkStringsOverride } from '../../i18n/strings.js';\nimport { ActivityErrorBoundary } from '../ActivityErrorBoundary.js';\nimport type { ActivityRenderer } from '../ActivitySequence/index.js';\nimport { Dictation } from '../Dictation/index.js';\nimport { FillInTheBlanks } from '../FillInTheBlanks/index.js';\nimport { GapSelect } from '../GapSelect/index.js';\nimport { MultipleChoice } from '../MultipleChoice/index.js';\nimport { ReadAloud } from '../ReadAloud/index.js';\nimport type { RecordingBinding } from '../ReadAloud/ReadAloud.js';\nimport type { HtmlSanitizer, MediaBudgetBinding, RenderMode } from '../types.js';\nimport { WrittenResponse } from '../WrittenResponse/index.js';\n\n/**\n * The option-shuffle seed a preview uses when none is given. Fixed, so a\n * shuffled question holds still while its author edits it instead of\n * re-ordering on every remount.\n */\nconst PREVIEW_SHUFFLE_SEED = 'lk-activity-preview';\n\n/**\n * The slot a previewed activity stands in for. A recording's play budget is\n * keyed to it and lives only in this mount: the preview counts plays so an\n * author hears the limit a learner gets, and records none of them.\n */\nconst PREVIEW_SLOT_ID = 'preview';\n\n/** Numbers the takes a preview mints keys for, so two are never the same take. */\nlet previewTakeCount = 0;\n\n/**\n * The store a previewed read-aloud records into: it keys the take so the whole\n * flow — record, play it back, submit — runs for the author, and keeps it\n * nowhere, like every other thing a preview does not record.\n *\n * It judges nothing, deliberately. `assess` is optional precisely so this can\n * exist: an author trying a reading out has no assessor to point at, and a\n * preview that demanded one would refuse to render the most common case. The\n * default `practice` mode then shows the \"assessment is not available\" notice,\n * which is the truth about this binding rather than a failure.\n */\nconst PREVIEW_RECORDING: RecordingBinding = {\n upload: async (take) => {\n previewTakeCount += 1;\n return {\n key: `${PREVIEW_SLOT_ID}-take-${previewTakeCount}`,\n mimeType: take.mimeType,\n durationMs: take.durationMs,\n };\n },\n};\n\nexport interface ActivityPreviewProps {\n /**\n * The activity as an editor holds it right now, finished or not. It is checked\n * with `validateDraft` before anything renders — by content, on every render —\n * so a half-written question never reaches a component that assumes a valid\n * one.\n */\n draft: unknown;\n /** The mode to preview in. Defaults to `practice`. */\n renderMode?: RenderMode;\n /**\n * A learner response to show as if a learner had given it. In `practice` and\n * `exam` it seeds the answer, which stays editable; in `review` it is the\n * submitted answer, marked by `evaluate()` unless `outcome` is given.\n */\n response?: LearnerResponse;\n /**\n * The outcome `review` marks the response with, instead of the one\n * `evaluate()` computes — which is how to preview a returned grade on a written\n * response, since the SDK cannot score one. Ignored in other modes.\n */\n outcome?: ItemOutcome;\n /**\n * Rendered in place of the activity while the draft is not complete, with the\n * issues `validateDraft` found — so an editor can list them in its own words.\n * The issue messages are English, and a preview that rendered them would put\n * untranslatable text on screen. Without it, the preview shows the\n * `previewIncomplete` or `previewInvalid` string.\n */\n fallback?: (result: DraftNotComplete) => ReactNode;\n /**\n * Renderers for activity types beyond the built-ins, keyed by `type`, as on\n * `<ActivitySequence>`. An entry receives the shared prop contract and\n * nothing else, so — like the shuffle seed below — the in-memory recording\n * binding a previewed read-aloud is given does not reach one.\n */\n renderers?: Readonly<Record<string, ActivityRenderer>>;\n /**\n * Seeds `<MultipleChoice>`'s option shuffle. Defaults to a fixed seed, so the\n * order holds while options are edited; adding or removing one deals them\n * again, because the shuffle orders by position. A `renderers` entry is given\n * no seed, as on `<ActivitySequence>`.\n */\n shuffleSeed?: string;\n /** Renders author-supplied rich text. See `HtmlSanitizer`. */\n sanitizeHtml?: HtmlSanitizer;\n /** Overrides the SDK's chrome text, for the preview's notice and the activity alike. */\n strings?: LkStringsOverride;\n /** Per-instance token overrides, passed to the activity. */\n theme?: Partial<ThemeTokens>;\n /** BCP 47 tag of the interface language, passed to the activity. */\n locale?: string;\n}\n\ntype Marking = { kind: 'marked'; outcome: ItemOutcome } | { kind: 'failed'; error: Error };\n\n/**\n * Renders an activity from an editor's draft, in any render mode, with a\n * simulated learner response — and renders a notice instead while the draft is\n * not an activity yet.\n *\n * Nothing it renders is recorded: no callback is wired, so a practice attempt in\n * a preview scores locally and goes nowhere, and a recording's play limit is\n * counted in memory only.\n *\n * A draft with no string `type`, a type nobody registered, and a `response` of a\n * different type from the draft are wiring errors, and throw.\n */\nexport function ActivityPreview({\n draft,\n renderMode = 'practice',\n response,\n outcome,\n fallback,\n renderers,\n shuffleSeed,\n sanitizeHtml,\n strings,\n theme,\n locale,\n}: ActivityPreviewProps) {\n const s = useLkStrings(strings);\n const type = isRecord(draft) && typeof draft.type === 'string' ? draft.type : undefined;\n\n // Validated on the draft's CONTENT, not its identity. The activity components\n // restart whenever `data` changes identity, and an editor that rebuilds its\n // payload on every change would otherwise restart the question an author is\n // trying out each time anything else on the page was edited. The key is read\n // on every render, so a draft changed in place is checked again too.\n const contentKey = contentKeyOf(draft);\n // biome-ignore lint/correctness/useExhaustiveDependencies: the draft's content (contentKey) is the trigger, not its identity\n const result = useMemo(\n () => (type === undefined ? undefined : validateDraft(type as ActivityType, draft)),\n [type, contentKey],\n );\n const activity = result?.status === 'complete' ? result.data : undefined;\n const responseFits = response === undefined || response.type === type;\n const responseKey = response === undefined ? 'none' : contentKeyOf(response);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: the response's content (responseKey) is the trigger, not its identity\n const marking = useMemo((): Marking | undefined => {\n if (renderMode !== 'review' || activity === undefined) {\n return undefined;\n }\n if (outcome !== undefined) {\n return { kind: 'marked', outcome };\n }\n if (response === undefined || !responseFits) {\n return undefined;\n }\n try {\n return { kind: 'marked', outcome: evaluate(activity, response) };\n } catch (thrown) {\n // Scored here, during this component's own render, where no error boundary\n // inside the activity can catch it — so it is handed to one below.\n return {\n kind: 'failed',\n error: thrown instanceof Error ? thrown : new Error(String(thrown)),\n };\n }\n }, [renderMode, activity, outcome, responseKey, responseFits]);\n\n const activityId = activity?.id;\n const mediaBudget = useMemo<MediaBudgetBinding>(\n () => ({\n key: slotMediaKey(PREVIEW_SLOT_ID),\n slotId: PREVIEW_SLOT_ID,\n index: 0,\n ...(activityId !== undefined ? { activityId } : {}),\n }),\n [activityId],\n );\n\n // All hooks are called before these throws, so hook order stays stable.\n if (type === undefined || result === undefined) {\n throw new Error(\n '<ActivityPreview> needs a draft object with a string `type`, to know which activity to check and render.',\n );\n }\n // Checked against the draft's own type, whatever state the draft is in. A\n // mis-wired response is a wiring error however unfinished the draft is, and\n // waiting for the draft to be complete would throw on the very edit that\n // completes it.\n if (response !== undefined && !responseFits) {\n throw new Error(\n `<ActivityPreview> was given a \"${response.type}\" response for a \"${type}\" activity.`,\n );\n }\n if (result.status !== 'complete') {\n if (fallback !== undefined) {\n return <>{fallback(result)}</>;\n }\n return (\n <div\n className=\"lk-preview-unavailable\"\n role=\"note\"\n data-status={result.status}\n {...(locale !== undefined ? { lang: locale } : {})}\n >\n {result.status === 'invalid' ? s.previewInvalid : s.previewIncomplete}\n </div>\n );\n }\n const data = result.data;\n\n // A different simulated response, or a different mode, mounts the activity\n // afresh, play count included: a seeded answer is read at mount, and a practice\n // attempt the author submitted must not carry over into an exam preview. So\n // does a different recording or playback policy, which is a different listening\n // budget — the transport reads its count once, when it mounts.\n const key = `${renderMode}:${responseKey}:${recordingKeyOf(data)}`;\n\n if (marking?.kind === 'failed') {\n // The response is one the scorer cannot read, or a registered scorer threw.\n // Shown as the activity's error fallback, as a render failure would be.\n return (\n <ActivityErrorBoundary key={key} activityTitle={data.title} strings={s}>\n <Rethrow error={marking.error} />\n </ActivityErrorBoundary>\n );\n }\n\n const shared = {\n renderMode,\n // Without a binding a budgeted recording counts nothing in `practice`, and in\n // `exam` the media component refuses to render at all — rightly, on a real\n // paper, where nothing would persist the count. A preview persists nothing by\n // design, so it keeps the count in memory and says so.\n mediaBudget,\n ...(sanitizeHtml !== undefined ? { sanitizeHtml } : {}),\n ...(strings !== undefined ? { strings } : {}),\n ...(theme !== undefined ? { theme } : {}),\n ...(locale !== undefined ? { locale } : {}),\n // Seeded rather than controlled, in every mode, exactly as `<ActivitySequence>`\n // hands a restored answer to its slots — so a renderer written for the\n // sequence reads it here too. `review` is read-only either way, and `key`\n // above re-seeds whenever the response changes.\n ...(response !== undefined ? { defaultValue: response } : {}),\n ...(marking !== undefined ? { outcome: marking.outcome } : {}),\n };\n\n const Custom = renderers?.[data.type];\n if (Custom !== undefined) {\n return <Custom key={key} data={data} {...shared} />;\n }\n switch (data.type) {\n case 'multiple-choice':\n return (\n <MultipleChoice\n key={key}\n data={data}\n shuffleSeed={shuffleSeed ?? PREVIEW_SHUFFLE_SEED}\n {...shared}\n />\n );\n case 'fill-in-the-blanks':\n return <FillInTheBlanks key={key} data={data} {...shared} />;\n case 'gap-select':\n return (\n <GapSelect\n key={key}\n data={data}\n shuffleSeed={shuffleSeed ?? PREVIEW_SHUFFLE_SEED}\n {...shared}\n />\n );\n case 'written-response':\n return <WrittenResponse key={key} data={data} {...shared} />;\n case 'dictation':\n return <Dictation key={key} data={data} {...shared} />;\n case 'read-aloud':\n return <ReadAloud key={key} data={data} recordingBinding={PREVIEW_RECORDING} {...shared} />;\n default:\n return (\n <div className=\"lk-preview-unsupported\" role=\"note\">\n {s.unsupportedActivity}\n </div>\n );\n }\n}\n\n/** Throws `error` while rendering, so the error boundary around it shows its fallback. */\nfunction Rethrow({ error }: { error: Error }): never {\n throw error;\n}\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/**\n * The recording and its playback policy — not its description, which changes\n * no budget — plus the slower file a dictation or a read-aloud carries, which\n * follows the same policy and must remount when it is swapped for another.\n */\nfunction recordingKeyOf(data: unknown): string {\n const media = isRecord(data) ? data.media : undefined;\n const slowMedia = isRecord(data) ? data.slowMedia : undefined;\n const slowUrl = isRecord(slowMedia) ? slowMedia.url : undefined;\n if (!isRecord(media) && slowUrl === undefined) {\n return '';\n }\n return contentKeyOf([\n isRecord(media) ? media.type : undefined,\n isRecord(media) ? media.url : undefined,\n isRecord(media) ? media.playback : undefined,\n slowUrl,\n ]);\n}\n\nconst identities = new WeakMap<object, number>();\nlet lastIdentity = 0;\n\n/** A key for a value compared by identity: the same object always gets the same one. */\nfunction identityKeyOf(value: object): string {\n let identity = identities.get(value);\n if (identity === undefined) {\n lastIdentity += 1;\n identity = lastIdentity;\n identities.set(value, identity);\n }\n return `#${identity}`;\n}\n\n/**\n * A string that changes exactly when a value's content does.\n *\n * Object keys are sorted, because key order is not content: a draft saved to a\n * JSON column comes back with its keys reordered. Every value is written in a\n * form no other value shares — JSON would write a non-finite number as `null`\n * and drop `undefined`, and those decide different issues. What JSON does not\n * describe — an instance of a class, a function, a reference back to an\n * enclosing object — is compared by identity, and a symbol by its description.\n */\nfunction contentKeyOf(value: unknown, enclosing: Set<object> = new Set()): string {\n switch (typeof value) {\n case 'string':\n return JSON.stringify(value);\n case 'number':\n // `String` keeps NaN, the infinities and every other number apart; only -0\n // needs saying.\n return Object.is(value, -0) ? '-0' : String(value);\n case 'bigint':\n return `${value}n`;\n case 'boolean':\n case 'undefined':\n return String(value);\n case 'symbol':\n return `Symbol(${JSON.stringify(value.description ?? null)})`;\n case 'function':\n return identityKeyOf(value);\n }\n // Every other `typeof` has returned above: this is `null`, or an object.\n if (value === null || typeof value !== 'object') {\n return 'null';\n }\n const prototype = Object.getPrototypeOf(value);\n const plain = Array.isArray(value) || prototype === Object.prototype || prototype === null;\n if (!plain || enclosing.has(value)) {\n return identityKeyOf(value);\n }\n enclosing.add(value);\n try {\n if (Array.isArray(value)) {\n return `[${Array.from(value, (item) => contentKeyOf(item, enclosing)).join(',')}]`;\n }\n const record = value as Record<string, unknown>;\n const fields = Object.keys(record)\n .sort()\n .map((field) => `${JSON.stringify(field)}:${contentKeyOf(record[field], enclosing)}`);\n return `{${fields.join(',')}}`;\n } finally {\n enclosing.delete(value);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/ActivityPreview/ActivityPreview.tsx"],"names":["useLkStrings","useMemo","validateDraft","evaluate","slotMediaKey","jsx","Fragment","ActivityErrorBoundary","MultipleChoice","FillInTheBlanks","GapSelect","WrittenResponse","Dictation","ReadAloud"],"mappings":"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","file":"chunk-UAYWLYFW.cjs","sourcesContent":["'use client';\n\nimport {\n type ActivityType,\n type DraftNotComplete,\n evaluate,\n type ItemOutcome,\n type LearnerResponse,\n slotMediaKey,\n type ThemeTokens,\n validateDraft,\n} from '@intellectif/lk-core';\nimport { type ReactNode, useMemo } from 'react';\nimport { useLkStrings } from '../../i18n/LkIntlProvider.js';\nimport type { LkStringsOverride } from '../../i18n/strings.js';\nimport { ActivityErrorBoundary } from '../ActivityErrorBoundary.js';\nimport type { ActivityRenderer } from '../ActivitySequence/index.js';\nimport { Dictation } from '../Dictation/index.js';\nimport { FillInTheBlanks } from '../FillInTheBlanks/index.js';\nimport { GapSelect } from '../GapSelect/index.js';\nimport { MultipleChoice } from '../MultipleChoice/index.js';\nimport { ReadAloud } from '../ReadAloud/index.js';\nimport type { RecordingBinding } from '../ReadAloud/ReadAloud.js';\nimport type { HtmlSanitizer, MediaBudgetBinding, RenderMode } from '../types.js';\nimport { WrittenResponse } from '../WrittenResponse/index.js';\n\n/**\n * The option-shuffle seed a preview uses when none is given. Fixed, so a\n * shuffled question holds still while its author edits it instead of\n * re-ordering on every remount.\n */\nconst PREVIEW_SHUFFLE_SEED = 'lk-activity-preview';\n\n/**\n * The slot a previewed activity stands in for. A recording's play budget is\n * keyed to it and lives only in this mount: the preview counts plays so an\n * author hears the limit a learner gets, and records none of them.\n */\nconst PREVIEW_SLOT_ID = 'preview';\n\n/** Numbers the takes a preview mints keys for, so two are never the same take. */\nlet previewTakeCount = 0;\n\n/**\n * The store a previewed read-aloud records into: it keys the take so the whole\n * flow — record, play it back, submit — runs for the author, and keeps it\n * nowhere, like every other thing a preview does not record.\n *\n * It judges nothing, deliberately. `assess` is optional precisely so this can\n * exist: an author trying a reading out has no assessor to point at, and a\n * preview that demanded one would refuse to render the most common case. The\n * default `practice` mode then shows the \"assessment is not available\" notice,\n * which is the truth about this binding rather than a failure.\n */\nconst PREVIEW_RECORDING: RecordingBinding = {\n upload: async (take) => {\n previewTakeCount += 1;\n return {\n key: `${PREVIEW_SLOT_ID}-take-${previewTakeCount}`,\n mimeType: take.mimeType,\n durationMs: take.durationMs,\n };\n },\n};\n\nexport interface ActivityPreviewProps {\n /**\n * The activity as an editor holds it right now, finished or not. It is checked\n * with `validateDraft` before anything renders — by content, on every render —\n * so a half-written question never reaches a component that assumes a valid\n * one.\n */\n draft: unknown;\n /** The mode to preview in. Defaults to `practice`. */\n renderMode?: RenderMode;\n /**\n * A learner response to show as if a learner had given it. In `practice` and\n * `exam` it seeds the answer, which stays editable; in `review` it is the\n * submitted answer, marked by `evaluate()` unless `outcome` is given.\n */\n response?: LearnerResponse;\n /**\n * The outcome `review` marks the response with, instead of the one\n * `evaluate()` computes — which is how to preview a returned grade on a written\n * response, since the SDK cannot score one. Ignored in other modes.\n */\n outcome?: ItemOutcome;\n /**\n * Rendered in place of the activity while the draft is not complete, with the\n * issues `validateDraft` found — so an editor can list them in its own words.\n * The issue messages are English, and a preview that rendered them would put\n * untranslatable text on screen. Without it, the preview shows the\n * `previewIncomplete` or `previewInvalid` string.\n */\n fallback?: (result: DraftNotComplete) => ReactNode;\n /**\n * Renderers for activity types beyond the built-ins, keyed by `type`, as on\n * `<ActivitySequence>`. An entry receives the shared prop contract and\n * nothing else, so — like the shuffle seed below — the in-memory recording\n * binding a previewed read-aloud is given does not reach one.\n */\n renderers?: Readonly<Record<string, ActivityRenderer>>;\n /**\n * Seeds `<MultipleChoice>`'s option shuffle. Defaults to a fixed seed, so the\n * order holds while options are edited; adding or removing one deals them\n * again, because the shuffle orders by position. A `renderers` entry is given\n * no seed, as on `<ActivitySequence>`.\n */\n shuffleSeed?: string;\n /** Renders author-supplied rich text. See `HtmlSanitizer`. */\n sanitizeHtml?: HtmlSanitizer;\n /** Overrides the SDK's chrome text, for the preview's notice and the activity alike. */\n strings?: LkStringsOverride;\n /** Per-instance token overrides, passed to the activity. */\n theme?: Partial<ThemeTokens>;\n /** BCP 47 tag of the interface language, passed to the activity. */\n locale?: string;\n}\n\ntype Marking = { kind: 'marked'; outcome: ItemOutcome } | { kind: 'failed'; error: Error };\n\n/**\n * Renders an activity from an editor's draft, in any render mode, with a\n * simulated learner response — and renders a notice instead while the draft is\n * not an activity yet.\n *\n * Nothing it renders is recorded: no callback is wired, so a practice attempt in\n * a preview scores locally and goes nowhere, and a recording's play limit is\n * counted in memory only.\n *\n * A draft with no string `type`, a type nobody registered, and a `response` of a\n * different type from the draft are wiring errors, and throw.\n */\nexport function ActivityPreview({\n draft,\n renderMode = 'practice',\n response,\n outcome,\n fallback,\n renderers,\n shuffleSeed,\n sanitizeHtml,\n strings,\n theme,\n locale,\n}: ActivityPreviewProps) {\n const s = useLkStrings(strings);\n const type = isRecord(draft) && typeof draft.type === 'string' ? draft.type : undefined;\n\n // Validated on the draft's CONTENT, not its identity. The activity components\n // restart whenever `data` changes identity, and an editor that rebuilds its\n // payload on every change would otherwise restart the question an author is\n // trying out each time anything else on the page was edited. The key is read\n // on every render, so a draft changed in place is checked again too.\n const contentKey = contentKeyOf(draft);\n // biome-ignore lint/correctness/useExhaustiveDependencies: the draft's content (contentKey) is the trigger, not its identity\n const result = useMemo(\n () => (type === undefined ? undefined : validateDraft(type as ActivityType, draft)),\n [type, contentKey],\n );\n const activity = result?.status === 'complete' ? result.data : undefined;\n const responseFits = response === undefined || response.type === type;\n const responseKey = response === undefined ? 'none' : contentKeyOf(response);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: the response's content (responseKey) is the trigger, not its identity\n const marking = useMemo((): Marking | undefined => {\n if (renderMode !== 'review' || activity === undefined) {\n return undefined;\n }\n if (outcome !== undefined) {\n return { kind: 'marked', outcome };\n }\n if (response === undefined || !responseFits) {\n return undefined;\n }\n try {\n return { kind: 'marked', outcome: evaluate(activity, response) };\n } catch (thrown) {\n // Scored here, during this component's own render, where no error boundary\n // inside the activity can catch it — so it is handed to one below.\n return {\n kind: 'failed',\n error: thrown instanceof Error ? thrown : new Error(String(thrown)),\n };\n }\n }, [renderMode, activity, outcome, responseKey, responseFits]);\n\n const activityId = activity?.id;\n const mediaBudget = useMemo<MediaBudgetBinding>(\n () => ({\n key: slotMediaKey(PREVIEW_SLOT_ID),\n slotId: PREVIEW_SLOT_ID,\n index: 0,\n ...(activityId !== undefined ? { activityId } : {}),\n }),\n [activityId],\n );\n\n // All hooks are called before these throws, so hook order stays stable.\n if (type === undefined || result === undefined) {\n throw new Error(\n '<ActivityPreview> needs a draft object with a string `type`, to know which activity to check and render.',\n );\n }\n // Checked against the draft's own type, whatever state the draft is in. A\n // mis-wired response is a wiring error however unfinished the draft is, and\n // waiting for the draft to be complete would throw on the very edit that\n // completes it.\n if (response !== undefined && !responseFits) {\n throw new Error(\n `<ActivityPreview> was given a \"${response.type}\" response for a \"${type}\" activity.`,\n );\n }\n if (result.status !== 'complete') {\n if (fallback !== undefined) {\n return <>{fallback(result)}</>;\n }\n return (\n <div\n className=\"lk-preview-unavailable\"\n role=\"note\"\n data-status={result.status}\n {...(locale !== undefined ? { lang: locale } : {})}\n >\n {result.status === 'invalid' ? s.previewInvalid : s.previewIncomplete}\n </div>\n );\n }\n const data = result.data;\n\n // A different simulated response, or a different mode, mounts the activity\n // afresh, play count included: a seeded answer is read at mount, and a practice\n // attempt the author submitted must not carry over into an exam preview. So\n // does a different recording or playback policy, which is a different listening\n // budget — the transport reads its count once, when it mounts.\n const key = `${renderMode}:${responseKey}:${recordingKeyOf(data)}`;\n\n if (marking?.kind === 'failed') {\n // The response is one the scorer cannot read, or a registered scorer threw.\n // Shown as the activity's error fallback, as a render failure would be.\n return (\n <ActivityErrorBoundary key={key} activityTitle={data.title} strings={s}>\n <Rethrow error={marking.error} />\n </ActivityErrorBoundary>\n );\n }\n\n const shared = {\n renderMode,\n // Without a binding a budgeted recording counts nothing in `practice`, and in\n // `exam` the media component refuses to render at all — rightly, on a real\n // paper, where nothing would persist the count. A preview persists nothing by\n // design, so it keeps the count in memory and says so.\n mediaBudget,\n ...(sanitizeHtml !== undefined ? { sanitizeHtml } : {}),\n ...(strings !== undefined ? { strings } : {}),\n ...(theme !== undefined ? { theme } : {}),\n ...(locale !== undefined ? { locale } : {}),\n // Seeded rather than controlled, in every mode, exactly as `<ActivitySequence>`\n // hands a restored answer to its slots — so a renderer written for the\n // sequence reads it here too. `review` is read-only either way, and `key`\n // above re-seeds whenever the response changes.\n ...(response !== undefined ? { defaultValue: response } : {}),\n ...(marking !== undefined ? { outcome: marking.outcome } : {}),\n };\n\n const Custom = renderers?.[data.type];\n if (Custom !== undefined) {\n return <Custom key={key} data={data} {...shared} />;\n }\n switch (data.type) {\n case 'multiple-choice':\n return (\n <MultipleChoice\n key={key}\n data={data}\n shuffleSeed={shuffleSeed ?? PREVIEW_SHUFFLE_SEED}\n {...shared}\n />\n );\n case 'fill-in-the-blanks':\n return <FillInTheBlanks key={key} data={data} {...shared} />;\n case 'gap-select':\n return (\n <GapSelect\n key={key}\n data={data}\n shuffleSeed={shuffleSeed ?? PREVIEW_SHUFFLE_SEED}\n {...shared}\n />\n );\n case 'written-response':\n return <WrittenResponse key={key} data={data} {...shared} />;\n case 'dictation':\n return <Dictation key={key} data={data} {...shared} />;\n case 'read-aloud':\n return <ReadAloud key={key} data={data} recordingBinding={PREVIEW_RECORDING} {...shared} />;\n default:\n return (\n <div className=\"lk-preview-unsupported\" role=\"note\">\n {s.unsupportedActivity}\n </div>\n );\n }\n}\n\n/** Throws `error` while rendering, so the error boundary around it shows its fallback. */\nfunction Rethrow({ error }: { error: Error }): never {\n throw error;\n}\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/**\n * The recording and its playback policy — not its description, which changes\n * no budget — plus the slower file a dictation or a read-aloud carries, which\n * follows the same policy and must remount when it is swapped for another.\n */\nfunction recordingKeyOf(data: unknown): string {\n const media = isRecord(data) ? data.media : undefined;\n const slowMedia = isRecord(data) ? data.slowMedia : undefined;\n const slowUrl = isRecord(slowMedia) ? slowMedia.url : undefined;\n if (!isRecord(media) && slowUrl === undefined) {\n return '';\n }\n return contentKeyOf([\n isRecord(media) ? media.type : undefined,\n isRecord(media) ? media.url : undefined,\n isRecord(media) ? media.playback : undefined,\n slowUrl,\n ]);\n}\n\nconst identities = new WeakMap<object, number>();\nlet lastIdentity = 0;\n\n/** A key for a value compared by identity: the same object always gets the same one. */\nfunction identityKeyOf(value: object): string {\n let identity = identities.get(value);\n if (identity === undefined) {\n lastIdentity += 1;\n identity = lastIdentity;\n identities.set(value, identity);\n }\n return `#${identity}`;\n}\n\n/**\n * A string that changes exactly when a value's content does.\n *\n * Object keys are sorted, because key order is not content: a draft saved to a\n * JSON column comes back with its keys reordered. Every value is written in a\n * form no other value shares — JSON would write a non-finite number as `null`\n * and drop `undefined`, and those decide different issues. What JSON does not\n * describe — an instance of a class, a function, a reference back to an\n * enclosing object — is compared by identity, and a symbol by its description.\n */\nfunction contentKeyOf(value: unknown, enclosing: Set<object> = new Set()): string {\n switch (typeof value) {\n case 'string':\n return JSON.stringify(value);\n case 'number':\n // `String` keeps NaN, the infinities and every other number apart; only -0\n // needs saying.\n return Object.is(value, -0) ? '-0' : String(value);\n case 'bigint':\n return `${value}n`;\n case 'boolean':\n case 'undefined':\n return String(value);\n case 'symbol':\n return `Symbol(${JSON.stringify(value.description ?? null)})`;\n case 'function':\n return identityKeyOf(value);\n }\n // Every other `typeof` has returned above: this is `null`, or an object.\n if (value === null || typeof value !== 'object') {\n return 'null';\n }\n const prototype = Object.getPrototypeOf(value);\n const plain = Array.isArray(value) || prototype === Object.prototype || prototype === null;\n if (!plain || enclosing.has(value)) {\n return identityKeyOf(value);\n }\n enclosing.add(value);\n try {\n if (Array.isArray(value)) {\n return `[${Array.from(value, (item) => contentKeyOf(item, enclosing)).join(',')}]`;\n }\n const record = value as Record<string, unknown>;\n const fields = Object.keys(record)\n .sort()\n .map((field) => `${JSON.stringify(field)}:${contentKeyOf(record[field], enclosing)}`);\n return `{${fields.join(',')}}`;\n } finally {\n enclosing.delete(value);\n }\n}\n"]}
|
|
@@ -36,6 +36,7 @@ var defaultTheme = {
|
|
|
36
36
|
"--lk-color-error": "#b91c1c",
|
|
37
37
|
"--lk-color-warning": "#b45309",
|
|
38
38
|
"--lk-color-focus-ring": "#18181b",
|
|
39
|
+
"--lk-color-media-accent": "#ffffff",
|
|
39
40
|
// ── Spacing ──────────────────────────────────────────────────────────────
|
|
40
41
|
"--lk-spacing-xs": "4px",
|
|
41
42
|
"--lk-spacing-sm": "8px",
|
|
@@ -122,5 +123,5 @@ exports.createTailwindTheme = createTailwindTheme;
|
|
|
122
123
|
exports.darkTheme = darkTheme;
|
|
123
124
|
exports.defaultTheme = defaultTheme;
|
|
124
125
|
exports.useTheme = useTheme;
|
|
125
|
-
//# sourceMappingURL=chunk-
|
|
126
|
-
//# sourceMappingURL=chunk-
|
|
126
|
+
//# sourceMappingURL=chunk-UCKA22ZJ.cjs.map
|
|
127
|
+
//# sourceMappingURL=chunk-UCKA22ZJ.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/theme/dark-theme.ts","../src/theme/tokens.ts","../src/theme/tailwind.ts","../src/theme/ThemeProvider.tsx"],"names":["createContext","useSyncExternalStore","useMemo","jsx","useContext"],"mappings":"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","file":"chunk-UCKA22ZJ.cjs","sourcesContent":["import type { ThemeTokens } from '@intellectif/lk-core';\n\n/**\n * Dark-mode colour overrides, merged over {@link defaultTheme} by\n * `ThemeProvider`. Colours only — spacing/typography/shape/motion are\n * theme-invariant. All pairs verified WCAG 2.2 AA against the dark surface.\n */\nexport const darkTheme: Partial<ThemeTokens> = {\n '--lk-color-primary': '#fafafa',\n '--lk-color-primary-hover': '#e4e4e7',\n '--lk-color-surface': '#09090b',\n '--lk-color-surface-raised': '#18181b',\n '--lk-color-border': '#27272a',\n '--lk-color-text': '#fafafa',\n '--lk-color-text-muted': '#a1a1aa',\n '--lk-color-success': '#4ade80',\n '--lk-color-error': '#f87171',\n '--lk-color-warning': '#fbbf24',\n '--lk-color-focus-ring': '#fafafa',\n};\n","import type { ThemeTokens } from '@intellectif/lk-core';\n\n/**\n * Canonical default theme token values. `defaults.css` mirrors these exactly.\n * Palette is a neutral monochrome, deliberately unbranded, so the SDK carries\n * nobody's look out of the box; consumers rebrand via `ThemeProvider`. All\n * colour pairs are verified to meet WCAG 2.2 AA: 4.5:1 for normal text, 3:1 for\n * UI / focus ring (see theme/__tests__/contrast.test.ts).\n */\nexport const defaultTheme: ThemeTokens = {\n // ── Colours (light) — neutral monochrome; semantic success/error/warning\n // retained for status legibility ────────────────────────────────────────\n '--lk-color-primary': '#18181b',\n '--lk-color-primary-hover': '#27272a',\n '--lk-color-surface': '#ffffff',\n '--lk-color-surface-raised': '#fafafa',\n '--lk-color-border': '#e4e4e7',\n '--lk-color-text': '#18181b',\n '--lk-color-text-muted': '#52525b',\n '--lk-color-success': '#15803d',\n '--lk-color-error': '#b91c1c',\n '--lk-color-warning': '#b45309',\n '--lk-color-focus-ring': '#18181b',\n '--lk-color-media-accent': '#ffffff',\n\n // ── Spacing ──────────────────────────────────────────────────────────────\n '--lk-spacing-xs': '4px',\n '--lk-spacing-sm': '8px',\n '--lk-spacing-md': '16px',\n '--lk-spacing-lg': '24px',\n '--lk-spacing-xl': '32px',\n\n // ── Typography ───────────────────────────────────────────────────────────\n '--lk-font-family-base':\n 'system-ui, -apple-system, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif',\n '--lk-font-size-sm': '0.875rem',\n '--lk-font-size-base': '1rem',\n '--lk-font-size-lg': '1.125rem',\n '--lk-font-weight-normal': '400',\n '--lk-font-weight-bold': '700',\n '--lk-line-height-base': '1.5',\n\n // ── Shape ────────────────────────────────────────────────────────────────\n '--lk-radius-sm': '0.25rem',\n '--lk-radius-base': '0.5rem',\n '--lk-radius-lg': '0.75rem',\n\n // ── Motion ───────────────────────────────────────────────────────────────\n '--lk-transition-fast': '150ms ease',\n '--lk-transition-base': '250ms ease',\n};\n","import type { ThemeTokens } from '@intellectif/lk-core';\nimport { defaultTheme } from './tokens.js';\n\n/**\n * Shape consumed by a Tailwind config's `theme.extend`. Every entry is a\n * `var(--lk-token, <fallback>)` reference: the var keeps utilities live\n * (ThemeProvider / dark-mode override at runtime); the fallback makes them\n * work with zero setup (no provider, no `defaults.css` import).\n */\nexport interface TailwindThemeExtension {\n colors: Record<string, string>;\n spacing: Record<string, string>;\n borderRadius: Record<string, string>;\n fontFamily: Record<string, string>;\n fontSize: Record<string, string>;\n}\n\n/**\n * Token-prefix → Tailwind bucket. `--lk-font-weight-*`, `--lk-line-height-*`\n * and `--lk-transition-*` are intentionally absent: the first two have no\n * matching `theme.extend` group here, and the transition tokens hold a\n * `<duration> <easing>` shorthand that would emit invalid\n * `transition-duration: 150ms ease` if mapped to Tailwind's `transitionDuration`.\n */\nconst BUCKETS = [\n ['--lk-color-', 'colors'],\n ['--lk-spacing-', 'spacing'],\n ['--lk-radius-', 'borderRadius'],\n ['--lk-font-family-', 'fontFamily'],\n ['--lk-font-size-', 'fontSize'],\n] as const;\n\n/**\n * Converts SDK theme tokens into a Tailwind `theme.extend` object so Tailwind\n * projects consume the same `--lk-*` tokens as the components — one shared\n * source of truth rather than a parallel, conflicting palette.\n */\nexport function createTailwindTheme(theme: Partial<ThemeTokens>): TailwindThemeExtension {\n const merged: Record<string, string> = { ...defaultTheme, ...theme };\n const extension: TailwindThemeExtension = {\n colors: {},\n spacing: {},\n borderRadius: {},\n fontFamily: {},\n fontSize: {},\n };\n\n for (const [tokenName, fallback] of Object.entries(merged)) {\n for (const [prefix, bucket] of BUCKETS) {\n if (tokenName.startsWith(prefix)) {\n extension[bucket][`lk-${tokenName.slice(prefix.length)}`] =\n `var(${tokenName}, ${fallback})`;\n break;\n }\n }\n }\n\n return extension;\n}\n","'use client';\n\nimport type { ThemeTokens } from '@intellectif/lk-core';\nimport {\n type CSSProperties,\n createContext,\n type ReactNode,\n useContext,\n useMemo,\n useSyncExternalStore,\n} from 'react';\nimport { darkTheme } from './dark-theme.js';\nimport { defaultTheme } from './tokens.js';\n\nexport { darkTheme } from './dark-theme.js';\nexport { createTailwindTheme, type TailwindThemeExtension } from './tailwind.js';\nexport { defaultTheme } from './tokens.js';\n\nconst ThemeContext = createContext<ThemeTokens>(defaultTheme);\n\nconst DARK_QUERY = '(prefers-color-scheme: dark)';\n\n/** Subscribe to OS dark-mode changes; no-op when there is no `window`. */\nfunction subscribePrefersDark(onChange: () => void): () => void {\n if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {\n return () => {};\n }\n const mql = window.matchMedia(DARK_QUERY);\n mql.addEventListener('change', onChange);\n return () => mql.removeEventListener('change', onChange);\n}\n\n/** Current OS dark-mode preference; `false` when there is no `window`. */\nfunction getPrefersDark(): boolean {\n if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {\n return false;\n }\n return window.matchMedia(DARK_QUERY).matches;\n}\n\nexport interface ThemeProviderProps {\n /** Partial token overrides. When provided, dark auto-detection is disabled. */\n theme?: Partial<ThemeTokens>;\n children: ReactNode;\n}\n\n/**\n * Provides theme tokens to descendant activity components as scoped inline CSS\n * custom properties on a wrapper `<div>`, and via {@link useTheme}.\n *\n * Resolution: an explicit `theme` prop merges over {@link defaultTheme} (and\n * suppresses dark auto-detect, per Req 13.5). With no `theme` prop, the OS\n * `prefers-color-scheme: dark` preference auto-applies {@link darkTheme}.\n * SSR-safe: the server snapshot is always light, so hydration never mismatches.\n */\nexport function ThemeProvider({ theme, children }: ThemeProviderProps) {\n const prefersDark = useSyncExternalStore(subscribePrefersDark, getPrefersDark, () => false);\n\n const activeTheme = useMemo<ThemeTokens>(() => {\n if (theme !== undefined) {\n return { ...defaultTheme, ...theme };\n }\n return prefersDark ? { ...defaultTheme, ...darkTheme } : defaultTheme;\n }, [theme, prefersDark]);\n\n return (\n <ThemeContext.Provider value={activeTheme}>\n <div style={activeTheme as CSSProperties}>{children}</div>\n </ThemeContext.Provider>\n );\n}\n\n/** Returns the currently active theme tokens (defaults when no provider). */\nexport function useTheme(): ThemeTokens {\n return useContext(ThemeContext);\n}\n"]}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var chunkOD65OZIW_cjs = require('./chunk-OD65OZIW.cjs');
|
|
5
|
-
var
|
|
6
|
-
var
|
|
5
|
+
var chunk53YOZOGN_cjs = require('./chunk-53YOZOGN.cjs');
|
|
6
|
+
var chunkZ6TVOAO5_cjs = require('./chunk-Z6TVOAO5.cjs');
|
|
7
7
|
var lkCore = require('@intellectif/lk-core');
|
|
8
8
|
var react = require('react');
|
|
9
9
|
var jsxRuntime = require('react/jsx-runtime');
|
|
@@ -319,12 +319,12 @@ function PronunciationFeedback({
|
|
|
319
319
|
theme,
|
|
320
320
|
strings
|
|
321
321
|
}) {
|
|
322
|
-
const s =
|
|
322
|
+
const s = chunkZ6TVOAO5_cjs.useLkStrings(strings);
|
|
323
323
|
const ids = react.useId();
|
|
324
324
|
const [openWord, setOpenWord] = react.useState(null);
|
|
325
325
|
const checked = react.useMemo(() => checkEvidence(assessment), [assessment]);
|
|
326
326
|
const devError = react.useMemo(
|
|
327
|
-
() =>
|
|
327
|
+
() => chunk53YOZOGN_cjs.isDevelopment() && !checked.success ? new lkCore.ActivitySchemaError("read-aloud", checked.errors) : null,
|
|
328
328
|
[checked]
|
|
329
329
|
);
|
|
330
330
|
const words = react.useMemo(
|
|
@@ -530,8 +530,8 @@ function PronunciationFeedback({
|
|
|
530
530
|
);
|
|
531
531
|
}
|
|
532
532
|
function PronunciationFeedback2(props) {
|
|
533
|
-
const strings =
|
|
534
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
533
|
+
const strings = chunkZ6TVOAO5_cjs.useLkStrings(props.strings);
|
|
534
|
+
return /* @__PURE__ */ jsxRuntime.jsx(chunk53YOZOGN_cjs.ActivityErrorBoundary, { strings, children: /* @__PURE__ */ jsxRuntime.jsx(PronunciationFeedback, { ...props }) });
|
|
535
535
|
}
|
|
536
536
|
|
|
537
537
|
exports.PronunciationFeedback = PronunciationFeedback2;
|
|
@@ -543,5 +543,5 @@ exports.readAssessResult = readAssessResult;
|
|
|
543
543
|
exports.readEvidence = readEvidence;
|
|
544
544
|
exports.readOutcome = readOutcome;
|
|
545
545
|
exports.usePlaybackRefusal = usePlaybackRefusal;
|
|
546
|
-
//# sourceMappingURL=chunk-
|
|
547
|
-
//# sourceMappingURL=chunk-
|
|
546
|
+
//# sourceMappingURL=chunk-WKOV25NP.cjs.map
|
|
547
|
+
//# sourceMappingURL=chunk-WKOV25NP.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/shared/playback-refusal.ts","../src/components/shared/read-grade.ts","../src/components/PronunciationFeedback/PronunciationFeedback.tsx","../src/components/PronunciationFeedback/index.tsx"],"names":["useState","useCallback","validateSpeechAssessment","useLkStrings","useId","useMemo","isDevelopment","ActivitySchemaError","alignReadAloud","useRef","useEffect","localeDirectionOf","jsxs","jsx","Fragment","PronunciationFeedback","ActivityErrorBoundary"],"mappings":"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","file":"chunk-YM64MS4G.cjs","sourcesContent":["'use client';\n\nimport { useCallback, useState } from 'react';\n\n/**\n * Whether the page refused to play the learner's own take, and the handler\n * every element that plays it reports a refusal through.\n *\n * The take is played from a `blob:` URL — the preview of a take not yet sent —\n * or from a link a review minted, and a page can refuse either without a word:\n * a Content-Security-Policy whose `media-src` does not allow `blob:` blocks the\n * load, the element fires `error`, and every control that plays it goes on\n * looking as if it works. So the refusal is decided in one place, by the URL\n * that was refused: a new take is a new URL and starts out playable again, and\n * a refusal an element reports after it was handed another URL cannot mark the\n * new one.\n *\n * `refuse` takes the element, not the URL, and reads the address the element\n * is loading at the moment it fails: an `error` belongs to the source the\n * element holds when it fires, and a closure's URL may already be a render\n * behind it.\n */\nexport function usePlaybackRefusal(url: string | null | undefined): {\n refused: boolean;\n refuse: (element: HTMLMediaElement) => void;\n} {\n const [refusedUrl, setRefusedUrl] = useState<string | null>(null);\n const refuse = useCallback((element: HTMLMediaElement) => {\n const source = element.getAttribute('src');\n if (source !== null) {\n setRefusedUrl(source);\n }\n }, []);\n return { refused: url !== null && url !== undefined && url === refusedUrl, refuse };\n}\n\n/**\n * Whether a rejected `play()` is the page refusing the source, rather than an\n * autoplay policy refusing the gesture. Only the first is the take's to report:\n * an autoplay refusal says nothing about whether the take can be played.\n */\nexport function isSourceRefusal(error: unknown): boolean {\n return (\n typeof error === 'object' &&\n error !== null &&\n (error as { name?: unknown }).name === 'NotSupportedError'\n );\n}\n","'use client';\n\nimport type {\n CriterionScore,\n GradeRecord,\n ReadAloudDimension,\n ScoringDetail,\n ScoringOutcome,\n SpeechAssessment,\n} from '@intellectif/lk-core';\n\n/**\n * The one reader of a grade that arrives from a host.\n *\n * Nothing validates a `GradeRecord`, an `ItemOutcome` or an assess result on\n * the way in: each is the application's, it crosses a network, and a field a\n * backend serialised as `null`, as a string or as an object is the ordinary way\n * to meet one. Every render path used to dereference them in its own way, so\n * every guard added for one shape left its sibling open — `criteria: null`\n * guarded and `criteria: [null]` not, a numeric `score` guarded and a string\n * `maxScore` shown as 8200%, `feedback` as an object taking a whole activity\n * down, `passed: null` dropping a grade from every callback in development and\n * sending an invalid statement in production.\n *\n * So the question \"what did the host send?\" has one answer, given here. The\n * panel, the outcome summary, the announcement, the decision about who shows\n * the score, `onComplete` and the xAPI statement read ONLY what these functions\n * return, and a payload they refuse is shown as could-not-be-graded — never the\n * error boundary, never `NaN`, never a percentage invented from a string.\n *\n * The rules, once:\n *\n * - **A required field is well-formed or the grade is refused.** `score` and\n * `maxScore` are finite numbers, `maxScore` above 0 and `score` between 0 and\n * it; `passed` is a boolean. A numeric string is not a number: `\"100\"` is how\n * a grade out of 100 turned into 8200%, and coercing it would only move the\n * guess somewhere else.\n * - **An optional field is absent when it is `undefined` or `null`** — how a\n * backend writes an absent optional — and otherwise well-formed or dropped.\n * `feedback` that is not a string is no feedback.\n * - **`criteria` keeps each well-formed entry and drops the rest.** Criteria are\n * named rows, each independent: an entry that cannot be read names no row.\n * - **`details` is read whole or not at all.** It is the word marks in order,\n * and a list with one word quietly missing would tell a learner they never\n * read a word they did.\n * - **Nothing here throws.** A payload whose getter throws is a payload that\n * cannot be read.\n */\n\n/** Marks a grade as read by {@link readGrade}. Type-only: it never exists at run time. */\ndeclare const READ: unique symbol;\n\n/**\n * A grade {@link readGrade} has checked: `0 <= score <= maxScore`, `maxScore >\n * 0`, both finite, `passed` a boolean, `feedback` a string or `null`, and\n * `criteria` and `details` (when present) holding only well-formed entries.\n * Still a `GradeRecord`, so it can be handed to anything that takes one — and\n * reading it again gives the same grade.\n */\nexport type ReadGrade = GradeRecord & { readonly [READ]: true };\n\n/** A stored outcome, as a renderer may show it. */\nexport type OutcomeReading =\n /** A grade to show: the outcome's own for `scored`, its `grade` for `graded`. */\n | { kind: 'graded'; status: 'scored' | 'graded'; grade: ReadGrade }\n | { kind: 'deferred' }\n /** `code` is a developer's label: put on an attribute, never shown. */\n | { kind: 'unscorable'; code: string | undefined }\n /** Claimed a grade, or claimed nothing a renderer knows, and could not be read. */\n | { kind: 'unreadable'; status: 'scored' | 'graded' | undefined };\n\n/** An assessor's answer, as a renderer and a statement may use it. */\nexport type AssessReading =\n | {\n status: 'graded';\n /** `null` when what came back cannot be read as a grade. */\n grade: ReadGrade | null;\n /** The evidence when it is an object at all; whether it VALIDATES is the panel's question. */\n assessment: SpeechAssessment | null;\n recognizedText: string | undefined;\n }\n | { status: 'unscorable'; code: string | undefined }\n | { status: 'failed'; retryable: boolean };\n\n/** One dimension row: a whole percentage, or `undefined` for a dimension nobody measured. */\nexport interface DimensionReading {\n dimension: ReadAloudDimension;\n percent: number | undefined;\n}\n\n/**\n * Every dimension a read-aloud grade can weigh, in the order a learner reads\n * them: what was said, how it flowed, how much of it was there, and how it was\n * pitched. Fixed rather than derived from the evidence, so a dimension the\n * engine did not measure is reported as unmeasured instead of vanishing.\n */\nconst DIMENSIONS: readonly ReadAloudDimension[] = [\n 'accuracy',\n 'fluency',\n 'completeness',\n 'prosody',\n];\n\nconst OUTCOMES: readonly ScoringOutcome[] = [\n 'correct',\n 'incorrect',\n 'correct-omission',\n 'incorrect-omission',\n];\n\n/**\n * How far past its own maximum a score may sit and still be read as that\n * maximum. A grader that sums weighted parts lands on `1.0000000000000002`\n * for a perfect take as readily as on `1`, and \"could not be graded\" is the\n * wrong thing to tell the learner who earned it. Far below any difference a\n * whole percentage can show.\n */\nconst OVERSHOOT = 1e-9;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === 'number' && Number.isFinite(value);\n}\n\n/** An optional field a backend left out, written either way it writes one. */\nfunction isAbsent(value: unknown): value is null | undefined {\n return value === undefined || value === null;\n}\n\n/** A score on `0..max`, a hair of overshoot read as `max`; `null` for anything else. */\nfunction withinMax(score: unknown, max: number): number | null {\n if (!isFiniteNumber(score) || score < 0) {\n return null;\n }\n if (score <= max) {\n return score;\n }\n return score - max <= max * OVERSHOOT ? max : null;\n}\n\n/** A learner's or a reference response: a string, or strings. */\nfunction isResponse(value: unknown): value is string | string[] {\n return (\n typeof value === 'string' ||\n (Array.isArray(value) && value.every((entry) => typeof entry === 'string'))\n );\n}\n\n/** Runs a read that touches a host's object, whose getters may throw. */\nfunction guarded<T>(read: () => T, refused: T): T {\n try {\n return read();\n } catch {\n return refused;\n }\n}\n\nfunction readCriterion(value: unknown): CriterionScore | null {\n if (!isRecord(value) || typeof value.name !== 'string') {\n return null;\n }\n const { maxScore, notApplicable } = value;\n if (!isAbsent(maxScore) && !(isFiniteNumber(maxScore) && maxScore > 0)) {\n return null;\n }\n if (!isAbsent(notApplicable) && typeof notApplicable !== 'boolean') {\n return null;\n }\n // `CriterionScore.maxScore` defaults to 1, the SDK's scaled convention.\n const score = isAbsent(value.score) ? undefined : withinMax(value.score, maxScore ?? 1);\n if (score === null) {\n return null;\n }\n return {\n name: value.name,\n ...(score !== undefined ? { score } : {}),\n ...(!isAbsent(maxScore) ? { maxScore } : {}),\n ...(notApplicable === true ? { notApplicable } : {}),\n };\n}\n\nfunction readDetail(value: unknown): ScoringDetail | null {\n if (!isRecord(value)) {\n return null;\n }\n const { itemId, correct, outcome, learnerResponse, correctResponse, weight, score } = value;\n if (\n typeof itemId !== 'string' ||\n typeof correct !== 'boolean' ||\n !isResponse(learnerResponse) ||\n !isResponse(correctResponse)\n ) {\n return null;\n }\n const checkedOutcome = OUTCOMES.find((known) => known === outcome);\n if (!isAbsent(outcome) && checkedOutcome === undefined) {\n return null;\n }\n if (!isAbsent(weight) && !isFiniteNumber(weight)) {\n return null;\n }\n // A detail's own score is a fraction of 1.\n const checkedScore = isAbsent(score) ? undefined : withinMax(score, 1);\n if (checkedScore === null) {\n return null;\n }\n return {\n itemId,\n correct,\n learnerResponse,\n correctResponse,\n ...(checkedOutcome !== undefined ? { outcome: checkedOutcome } : {}),\n ...(!isAbsent(weight) ? { weight } : {}),\n ...(checkedScore !== undefined ? { score: checkedScore } : {}),\n };\n}\n\nfunction readDetails(value: unknown): ScoringDetail[] | undefined {\n if (!Array.isArray(value)) {\n return undefined;\n }\n const details: ScoringDetail[] = [];\n for (const entry of value) {\n const detail = readDetail(entry);\n if (detail === null) {\n return undefined;\n }\n details.push(detail);\n }\n return details;\n}\n\n/**\n * A host's grade as a checked copy, or `null` when it carries no grade that can\n * be shown or reported. See the module notes for the rules.\n */\nexport function readGrade(value: unknown): ReadGrade | null {\n return guarded(() => {\n if (!isRecord(value)) {\n return null;\n }\n const { maxScore, passed } = value;\n if (!isFiniteNumber(maxScore) || maxScore <= 0 || typeof passed !== 'boolean') {\n return null;\n }\n const score = withinMax(value.score, maxScore);\n if (score === null) {\n return null;\n }\n const criteria = Array.isArray(value.criteria)\n ? value.criteria.flatMap((entry) => {\n const criterion = readCriterion(entry);\n return criterion === null ? [] : [criterion];\n })\n : undefined;\n const details = readDetails(value.details);\n const grade: GradeRecord = {\n score,\n maxScore,\n passed,\n feedback: typeof value.feedback === 'string' ? value.feedback : null,\n ...(criteria !== undefined ? { criteria } : {}),\n ...(details !== undefined ? { details } : {}),\n };\n return grade as ReadGrade;\n }, null);\n}\n\n/** A read grade as a fraction of 1: in `0..1`, because the reader made it so. */\nexport function fractionOfGrade(grade: ReadGrade): number {\n return grade.score / grade.maxScore;\n}\n\n/** A read grade as a whole percentage: in `0..100`, because the reader made it so. */\nexport function percentOfGrade(grade: ReadGrade): number {\n return Math.round(fractionOfGrade(grade) * 100);\n}\n\n/**\n * A stored outcome as a renderer may show it, or `undefined` for none —\n * `null` included, which is how a backend writes an absent optional.\n *\n * A `graded` outcome is read through its `grade`, the record\n * `outcomeFromGrade` mirrors onto it, so the summary and the panel beside it\n * can never show two different numbers; and it must be well-formed as a whole,\n * its own `score`, `maxScore` and `passed` included — a payload with a corrupt\n * copy of the grade is not one to pick a side of.\n */\nexport function readOutcome(value: unknown): OutcomeReading | undefined {\n if (isAbsent(value)) {\n return undefined;\n }\n return guarded(\n (): OutcomeReading => {\n if (!isRecord(value)) {\n return { kind: 'unreadable', status: undefined };\n }\n switch (value.status) {\n case 'deferred':\n return { kind: 'deferred' };\n case 'unscorable':\n return {\n kind: 'unscorable',\n code: typeof value.code === 'string' ? value.code : undefined,\n };\n case 'scored': {\n const grade = readGrade(value);\n return grade === null\n ? { kind: 'unreadable', status: 'scored' }\n : { kind: 'graded', status: 'scored', grade };\n }\n case 'graded': {\n const grade = readGrade(value.grade);\n return grade === null || readGrade(value) === null\n ? { kind: 'unreadable', status: 'graded' }\n : { kind: 'graded', status: 'graded', grade };\n }\n default:\n return { kind: 'unreadable', status: undefined };\n }\n },\n { kind: 'unreadable', status: undefined },\n );\n}\n\n/**\n * An assessor's answer as a renderer and a statement may use it.\n *\n * `failed` and `unscorable` need little: a `retryable` that is not `true`\n * offers no retry, which never spends an application's money on a guess, and a\n * `code` that is not a string is no code. Everything else — a `graded` result,\n * and anything that is not an object or names no status this component knows —\n * is read as a judgement: its grade when one can be read, its evidence when it\n * is an object. A judgement with neither is shown as could-not-be-graded.\n */\nexport function readAssessResult(value: unknown): AssessReading {\n const nothing: AssessReading = {\n status: 'graded',\n grade: null,\n assessment: null,\n recognizedText: undefined,\n };\n return guarded((): AssessReading => {\n if (!isRecord(value)) {\n return nothing;\n }\n if (value.status === 'failed') {\n return { status: 'failed', retryable: value.retryable === true };\n }\n if (value.status === 'unscorable') {\n return {\n status: 'unscorable',\n code: typeof value.code === 'string' ? value.code : undefined,\n };\n }\n if (value.status !== 'graded') {\n return nothing;\n }\n const assessment = readEvidence(value.assessment);\n const recognizedText = guarded(\n () =>\n typeof assessment?.recognizedText === 'string' ? assessment.recognizedText : undefined,\n undefined,\n );\n return { status: 'graded', grade: readGrade(value.grade), assessment, recognizedText };\n }, nothing);\n}\n\n/**\n * Evidence worth handing to the panel: an object. Whether it validates is the\n * panel's to decide, because what a refusal costs differs by mode.\n */\nexport function readEvidence(value: unknown): SpeechAssessment | null {\n return isRecord(value) ? (value as unknown as SpeechAssessment) : null;\n}\n\n/** One criterion's whole percentage of its own maximum, or `undefined` when it carries none. */\nfunction percentOfCriterion(criterion: CriterionScore): number | undefined {\n if (criterion.notApplicable === true || criterion.score === undefined) {\n return undefined;\n }\n return Math.round((criterion.score / (criterion.maxScore ?? 1)) * 100);\n}\n\n/**\n * The dimension rows, from one source for the whole set and never a mix: the\n * grade's criteria when it has any it can read, and the evidence's own scores\n * otherwise. A dimension pulled out of the evidence and set beside graded ones\n * would read as if it had counted towards the grade.\n *\n * The evidence is read as defensively as the grade: in production the panel\n * shows these rows even for evidence the validator refused, which can carry\n * anything at all under `scores`. `scale` is 100 by schema, so an evidence\n * score is already a percentage — and one outside `0..100` is not one.\n */\nexport function readDimensions(\n assessment: unknown,\n grade: ReadGrade | null | undefined,\n): DimensionReading[] {\n const criteria = grade?.criteria ?? [];\n if (criteria.length > 0) {\n return DIMENSIONS.map((dimension) => {\n const criterion = criteria.find((entry) => entry.name === dimension);\n return {\n dimension,\n percent: criterion === undefined ? undefined : percentOfCriterion(criterion),\n };\n });\n }\n const scores = guarded(() => (isRecord(assessment) ? assessment.scores : undefined), undefined);\n return DIMENSIONS.map((dimension) => {\n const score = withinMax(\n guarded(() => (isRecord(scores) ? scores[dimension] : undefined), undefined),\n 100,\n );\n // Rounded rather than reformatted: the engine's own number is what was graded.\n return { dimension, percent: score === null ? undefined : Math.round(score) };\n });\n}\n","'use client';\n\nimport {\n ActivitySchemaError,\n alignReadAloud,\n type GradeRecord,\n type ReadAloudData,\n type ReadAloudWordAlignment,\n type SpeechAssessment,\n type SpeechPhoneme,\n type SpeechWord,\n type ThemeTokens,\n type ValidationResult,\n validateSpeechAssessment,\n} from '@intellectif/lk-core';\nimport { type CSSProperties, useEffect, useId, useMemo, useRef, useState } from 'react';\nimport { localeDirectionOf } from '../../i18n/direction.js';\nimport { useLkStrings } from '../../i18n/LkIntlProvider.js';\nimport type { LkStrings, LkStringsOverride } from '../../i18n/strings.js';\nimport { isDevelopment } from '../_internal.js';\nimport { isSourceRefusal, usePlaybackRefusal } from '../shared/playback-refusal.js';\nimport { percentOfGrade, readDimensions, readGrade } from '../shared/read-grade.js';\n\n/**\n * Present for assistive technology, invisible on screen. Inline rather than\n * left to the optional skin, for the reason `<Dictation>` gives: the per-word\n * sentences are the marks' only channel for a screen reader, and a page that\n * does not load the skin would otherwise show every one of them beside its\n * word. Exported so `<ReadAloud>`, whose review fallback renders the same\n * marks from stored details, carries one definition rather than a copy.\n */\nexport const VISUALLY_HIDDEN: CSSProperties = {\n position: 'absolute',\n width: 1,\n height: 1,\n margin: -1,\n padding: 0,\n overflow: 'hidden',\n clip: 'rect(0 0 0 0)',\n clipPath: 'inset(50%)',\n whiteSpace: 'nowrap',\n border: 0,\n};\n\n/** The four marking states, in the order the legend lists them. */\nconst LEGEND_STATES: readonly ReadAloudWordAlignment['state'][] = [\n 'correct',\n 'mispronounced',\n 'omitted',\n 'inserted',\n];\n\nexport interface PronunciationFeedbackProps {\n /**\n * The item's reading and its language. Only these two fields, because they\n * are the only ones a mark depends on — everything else about the activity\n * belongs to whoever rendered it.\n */\n data: Pick<ReadAloudData, 'referenceText' | 'locale'>;\n /**\n * The assessor's evidence. Checked with `validateSpeechAssessment` before it\n * is aligned: see the note on this component about what a bad one costs.\n */\n assessment: SpeechAssessment;\n /**\n * The grade the evidence produced, when one exists. Its `criteria` are what\n * the dimensions are read from, because they are the numbers the learner was\n * actually graded on. A grade that cannot be read — a score that is not a\n * number between 0 and its maximum, a `passed` that is not a boolean — is\n * shown as could-not-be-graded, never as a percentage made up from it.\n */\n grade?: GradeRecord;\n /**\n * The learner's own take, playable. With it, each word that carries timings\n * gets a button that plays just that word. A take the page refuses to play —\n * a `blob:` URL under a Content-Security-Policy whose `media-src` does not\n * allow one, most often — offers no such button, and the panel says the take\n * cannot be played here.\n */\n audioUrl?: string;\n /**\n * Confidence above which a break note is shown, 0..1. **No default**: how\n * confident an engine has to be before a pause is worth telling a learner\n * about is a calibration, and the SDK has no calibrated answer. Without it no\n * break note is shown at all.\n */\n breakThreshold?: number;\n /** The same, for the monotone note read off `assessment.prosody`. */\n monotoneThreshold?: number;\n /**\n * BCP 47 tag stamped as `lang` on the root: the INTERFACE language, the one\n * this component's own sentences are written in. It is not `data.locale`,\n * which is the language of the reading and is put on the words themselves.\n */\n locale?: string;\n /** Per-instance token overrides, applied as inline CSS vars on the root. */\n theme?: Partial<ThemeTokens>;\n /** Overrides the SDK's chrome text for this panel. See {@link LkIntlProvider}. */\n strings?: LkStringsOverride;\n}\n\n/**\n * What the validator says about evidence that may not even be readable. Its\n * cross-field rules read the value directly, so a getter that throws escapes\n * it — and evidence that cannot be read is evidence refused, not a reason to\n * take the grade beside it down.\n */\nfunction checkEvidence(assessment: unknown): ValidationResult<SpeechAssessment> {\n try {\n return validateSpeechAssessment(assessment);\n } catch {\n return {\n success: false,\n errors: [{ path: [], message: 'The assessment could not be read.', code: 'unreadable' }],\n };\n }\n}\n\n/** Whether a word carries anything a disclosure would have to show. */\nfunction hasDetail(word: SpeechWord | undefined): word is SpeechWord {\n if (word === undefined) {\n return false;\n }\n return (\n word.accuracy !== undefined ||\n (word.syllables !== undefined && word.syllables.length > 0) ||\n (word.phonemes !== undefined && word.phonemes.length > 0) ||\n word.breaks !== undefined ||\n (typeof word.startMs === 'number' && typeof word.durationMs === 'number')\n );\n}\n\n/** A confidence that clears the caller's threshold. No threshold, no note. */\nfunction past(confidence: number | undefined, threshold: number | undefined): boolean {\n return (\n threshold !== undefined &&\n typeof confidence === 'number' &&\n Number.isFinite(confidence) &&\n confidence > threshold\n );\n}\n\n/** One phoneme, named by its symbol or — when the engine named none — by its place. */\nfunction phonemeLabel(phoneme: SpeechPhoneme, index: number, s: LkStrings): string {\n return phoneme.symbol ?? s.pronunciationPhonemePosition(index + 1);\n}\n\n/**\n * What a screen reader hears for one marked word — the marks' only channel for\n * assistive technology, since the glyph and the decoration are both hidden from\n * it. Exported because `<ReadAloud>`'s review fallback marks the same four\n * states from stored details, and a second copy of these four sentences would\n * be a second thing to translate.\n *\n * Branches on `state` and **never** on `heard === ''`: an inserted word whose\n * text normalises to nothing carries the empty string too, and would otherwise\n * be announced as an omission.\n */\nexport function markSentence(entry: ReadAloudWordAlignment, s: LkStrings): string {\n switch (entry.state) {\n case 'correct':\n return s.pronunciationWordCorrect(entry.reference);\n case 'mispronounced':\n return s.pronunciationWordMispronounced(entry.reference);\n case 'omitted':\n return s.pronunciationWordOmitted(entry.reference);\n default:\n return s.pronunciationWordInserted(entry.heard);\n }\n}\n\n/**\n * The per-word marks of a read-aloud take, plus the dimensions they were\n * graded on.\n *\n * **A bad assessment never destroys a good grade.** `alignReadAloud` throws a\n * `TypeError` for evidence `validateSpeechAssessment` refuses, so this\n * component runs the validator first. In development the refusal is thrown as\n * an `ActivitySchemaError`, which is the package's dev-error convention and\n * puts the problem in front of whoever wired the adapter up. In production the\n * dimensions and the grade are rendered and the word list is left out — a\n * learner who earned 82% should see 82%, not \"this activity could not be\n * displayed\" from an error boundary.\n *\n * **Nor does a bad grade take the evidence down.** `grade` is read, not\n * trusted: a score that is not a number between 0 and its maximum, or a\n * `passed` that is not a boolean, is shown as could-not-be-graded beside the\n * dimensions and the marks, and criteria that cannot be read name no dimension.\n *\n * There is **no `renderMode`**: nothing here submits, grades or reveals an\n * answer key. A read-aloud item has none, and the marks exist only once a\n * server has graded the take, so there is no mode in which they must be\n * withheld.\n *\n * ```tsx\n * <PronunciationFeedback\n * data={item}\n * assessment={assessment}\n * grade={grade}\n * audioUrl={takeUrl}\n * breakThreshold={0.75}\n * monotoneThreshold={0.6}\n * />\n * ```\n */\nexport function PronunciationFeedback({\n data,\n assessment,\n grade,\n audioUrl,\n breakThreshold,\n monotoneThreshold,\n locale,\n theme,\n strings,\n}: PronunciationFeedbackProps) {\n const s = useLkStrings(strings);\n const ids = useId();\n const [openWord, setOpenWord] = useState<number | null>(null);\n\n const checked = useMemo(() => checkEvidence(assessment), [assessment]);\n\n const devError = useMemo(\n () =>\n isDevelopment() && !checked.success\n ? new ActivitySchemaError('read-aloud', checked.errors)\n : null,\n [checked],\n );\n\n // The checked copy, never the argument, for the same reason lk-core aligns\n // from it: a property getter cannot answer the validator one word and the\n // aligner another.\n const words = useMemo<ReadAloudWordAlignment[] | null>(\n () => (checked.success ? alignReadAloud(data, checked.data) : null),\n [checked, data],\n );\n\n // The grade as the one reader of a host's grade reads it: `undefined` when\n // none was given, and `null` when one was and cannot be shown. Everything\n // below that shows a number reads this and the dimension rows, never `grade`.\n const reading = useMemo(\n () => (grade === undefined || grade === null ? undefined : readGrade(grade)),\n [grade],\n );\n const dimensions = useMemo(() => readDimensions(assessment, reading), [assessment, reading]);\n\n // The take, for the per-word play buttons. A ref and an effect, never a read\n // during render: this component server-renders like every other one here.\n const audioRef = useRef<HTMLAudioElement>(null);\n const stopRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const playback = usePlaybackRefusal(audioUrl);\n // A take the page refused is offered to no button: pressed, each would do\n // nothing, which is the silent failure the note below replaces.\n const playable = audioUrl !== undefined && !playback.refused;\n useEffect(\n () => () => {\n if (stopRef.current !== null) {\n clearTimeout(stopRef.current);\n }\n },\n [],\n );\n\n // All hooks are called before this throw, so hook order stays stable.\n if (devError) {\n throw devError;\n }\n\n /** Plays one word out of the take, and stops at the end of it. */\n const playWord = (startMs: number, durationMs: number): void => {\n const element = audioRef.current;\n if (element === null) {\n return;\n }\n if (stopRef.current !== null) {\n clearTimeout(stopRef.current);\n }\n element.currentTime = startMs / 1000;\n try {\n void element.play().catch((error: unknown) => {\n // An autoplay refusal is not this component's to report; a source the\n // page will not load is, and the element's own `error` may not have\n // fired yet for an engine that loads nothing until asked.\n if (isSourceRefusal(error)) {\n playback.refuse(element);\n }\n });\n } catch {\n /* an engine with no media stack at all; the button simply does nothing */\n }\n stopRef.current = setTimeout(() => {\n stopRef.current = null;\n element.pause();\n }, durationMs);\n };\n\n // The reading's own language and the direction its tag names, put on the\n // words and on nothing else: the sentences beside them are interface text.\n // No `_`→`-` normalisation, unlike `<Dictation>` — `ReadAloudData.locale` is\n // canonical by schema, so there is nothing to normalise.\n const contentLang = typeof data.locale === 'string' ? data.locale : undefined;\n const contentDir = localeDirectionOf(data.locale);\n\n const alphabet = checked.success ? checked.data.phonemeAlphabet : undefined;\n const monotone = checked.success ? checked.data.prosody?.monotoneConfidence : undefined;\n // Read through `at`, not through an index: `wordIndex` belongs to a public\n // type a caller may have built by hand, and it is allowed to point nowhere.\n const evidenceWords: readonly SpeechWord[] = checked.success ? checked.data.words : [];\n\n return (\n <section\n className=\"lk-pf\"\n aria-label={s.pronunciationFeedbackLabel}\n lang={locale}\n style={theme as CSSProperties | undefined}\n >\n {reading !== undefined ? (\n // `.lk-pf-grade` is load-bearing beyond the skin: `<ReadAloud>` looks\n // for it after the commit to decide whether it must render the score\n // itself, so a grade is never lost between the two components. It\n // hands this panel only a grade it has already read, so the block it\n // finds always carries the score.\n //\n // `data-passed` only where there is a verdict: a grade that could not\n // be read has none, and styling it as a fail would invent one.\n <div\n className=\"lk-pf-grade\"\n {...(reading !== null ? { 'data-passed': String(reading.passed) } : {})}\n >\n <p className=\"lk-pf-score\">\n {reading === null\n ? s.couldNotBeGraded\n : s.scoreAnnouncement(percentOfGrade(reading), reading.passed)}\n </p>\n {/* The grader's words, isolated: their direction is their own, so an\n English comment in an Arabic interface keeps its full stop at its\n end. Their language is not guessed — feedback may be written in\n either the interface's language or the reading's. */}\n {reading?.feedback ? (\n <p className=\"lk-pf-grade-feedback\" dir=\"auto\">\n {reading.feedback}\n </p>\n ) : null}\n </div>\n ) : null}\n\n <dl className=\"lk-pf-dimensions\">\n {dimensions.map(({ dimension, percent }) => (\n <div className=\"lk-pf-dimension\" key={dimension} data-dimension={dimension}>\n <dt className=\"lk-pf-dimension-name\">{s.pronunciationDimension(dimension)}</dt>\n {/* An absent score is NEVER a 0: a dimension nobody measured and a\n dimension measured at nothing are different findings, and only\n one of them is the learner's. */}\n <dd className=\"lk-pf-dimension-score\">\n {percent === undefined ? s.pronunciationNotAssessed : `${percent}%`}\n </dd>\n </div>\n ))}\n </dl>\n\n {words !== null ? (\n <>\n {/* The list's name and the hidden sentences are interface text and\n keep the interface language; only the words carry the reading's.\n Its direction is the reading's, never resolved from the list's own\n text: the first strong character there is a hidden sentence. */}\n <ol className=\"lk-pf-words\" aria-label={s.pronunciationWordsLabel} dir={contentDir}>\n {words.map((entry, index) => {\n const sentence = markSentence(entry, s);\n const shown = entry.state === 'inserted' ? entry.heard : entry.reference;\n const word =\n entry.wordIndex === undefined ? undefined : evidenceWords.at(entry.wordIndex);\n const open = openWord === index;\n const panelId = `${ids}-w${index}`;\n return (\n <li\n // biome-ignore lint/suspicious/noArrayIndexKey: alignment order is the identity; words repeat\n key={index}\n className=\"lk-pf-word\"\n data-state={entry.state}\n >\n {/* The state's only channel for assistive technology, and\n exactly one channel: the same sentence as a `title` is an\n accessible description, which a screen reader reads\n straight after the name it duplicates. */}\n <span className=\"lk-visually-hidden\" style={VISUALLY_HIDDEN}>\n {sentence}\n </span>\n {/* Decoration: the glyph the skin draws and the word itself.\n Hidden from assistive technology, which already has the\n sentence above — and the glyph is never the only channel. */}\n <span\n className=\"lk-pf-word-text\"\n aria-hidden=\"true\"\n dir={contentDir ?? 'auto'}\n lang={contentLang}\n >\n {shown}\n </span>\n {hasDetail(word) ? (\n <>\n <button\n type=\"button\"\n className=\"lk-pf-word-toggle\"\n aria-expanded={open}\n aria-controls={panelId}\n onClick={() => setOpenWord(open ? null : index)}\n >\n {s.pronunciationWordDetails(shown)}\n </button>\n {open ? (\n <div id={panelId} className=\"lk-pf-word-detail\">\n <dl className=\"lk-pf-word-facts\">\n <dt>{s.pronunciationDimension('accuracy')}</dt>\n <dd>\n {word.accuracy === undefined\n ? s.pronunciationNotAssessed\n : `${Math.round(word.accuracy)}%`}\n </dd>\n {word.syllables !== undefined && word.syllables.length > 0 ? (\n <>\n <dt>{s.pronunciationSyllables}</dt>\n <dd>\n <ul className=\"lk-pf-syllables\">\n {word.syllables.map((syllable, position) => (\n <li\n // biome-ignore lint/suspicious/noArrayIndexKey: syllables are positional and repeat within a word\n key={position}\n dir={contentDir ?? 'auto'}\n lang={contentLang}\n >\n {syllable.grapheme === undefined\n ? syllable.text\n : s.pronunciationSyllableSpelling(\n syllable.text,\n syllable.grapheme,\n )}\n </li>\n ))}\n </ul>\n </dd>\n </>\n ) : null}\n {word.phonemes !== undefined && word.phonemes.length > 0 ? (\n <>\n <dt>{s.pronunciationPhonemes}</dt>\n <dd>\n <ul className=\"lk-pf-phonemes\">\n {word.phonemes.map((phoneme, position) => (\n <li\n // biome-ignore lint/suspicious/noArrayIndexKey: a word may sound the same phoneme twice\n key={position}\n className=\"lk-pf-phoneme\"\n >\n <span className=\"lk-pf-phoneme-symbol\">\n {phonemeLabel(phoneme, position, s)}\n </span>\n {phoneme.heardAs !== undefined &&\n phoneme.heardAs.length > 0 ? (\n <>\n <span className=\"lk-pf-heard-label\">\n {s.pronunciationHeardAs}\n </span>\n <ul className=\"lk-pf-heard-as\">\n {phoneme.heardAs.map((candidate, rank) => (\n <li\n // biome-ignore lint/suspicious/noArrayIndexKey: candidates are ranked and a symbol may repeat\n key={rank}\n >\n {candidate.symbol}\n </li>\n ))}\n </ul>\n </>\n ) : null}\n </li>\n ))}\n </ul>\n </dd>\n </>\n ) : null}\n </dl>\n {playable &&\n typeof word.startMs === 'number' &&\n typeof word.durationMs === 'number' ? (\n <button\n type=\"button\"\n className=\"lk-pf-word-play\"\n onClick={() =>\n playWord(word.startMs as number, word.durationMs as number)\n }\n >\n {s.pronunciationPlayWord(shown)}\n </button>\n ) : null}\n {past(word.breaks?.unexpected, breakThreshold) ? (\n <p className=\"lk-pf-break\" data-break=\"unexpected\">\n {s.pronunciationBreakUnexpected}\n </p>\n ) : null}\n {past(word.breaks?.missing, breakThreshold) ? (\n <p className=\"lk-pf-break\" data-break=\"missing\">\n {s.pronunciationBreakMissing}\n </p>\n ) : null}\n </div>\n ) : null}\n </>\n ) : null}\n </li>\n );\n })}\n </ol>\n <ul className=\"lk-pf-legend\">\n {LEGEND_STATES.map((state) => (\n <li key={state} data-state={state}>\n {s.pronunciationLegend(state)}\n </li>\n ))}\n </ul>\n {/* Only where there are symbols to explain, and only for the alphabet\n this note names. An engine that reported another one, or none at\n all, gets no note rather than a wrong one. */}\n {alphabet === 'ipa' ? <p className=\"lk-pf-alphabet\">{s.pronunciationIpaNote}</p> : null}\n </>\n ) : null}\n\n {past(monotone, monotoneThreshold) ? (\n <p className=\"lk-pf-monotone\" role=\"note\">\n {s.pronunciationMonotone}\n </p>\n ) : null}\n\n {audioUrl === undefined ? null : playback.refused ? (\n <p className=\"lk-pf-audio-unavailable\" role=\"note\">\n {s.readAloudPlaybackUnavailable}\n </p>\n ) : (\n // biome-ignore lint/a11y/useMediaCaption: the learner's own take has no caption track to offer, and this element is never played as content — it carries no controls and exists only so one word can be replayed from a button that names it\n <audio\n ref={audioRef}\n className=\"lk-pf-audio\"\n src={audioUrl}\n preload=\"metadata\"\n onError={(event) => playback.refuse(event.currentTarget)}\n />\n )}\n </section>\n );\n}\n","'use client';\n\nimport { useLkStrings } from '../../i18n/LkIntlProvider.js';\nimport { ActivityErrorBoundary } from '../ActivityErrorBoundary.js';\nimport {\n PronunciationFeedback as PronunciationFeedbackCore,\n type PronunciationFeedbackProps,\n} from './PronunciationFeedback.js';\n\nexport type { PronunciationFeedbackProps } from './PronunciationFeedback.js';\n\n/**\n * Public pronunciation-feedback panel: the core wrapped in\n * `ActivityErrorBoundary` so a render failure (the dev throw for evidence\n * `validateSpeechAssessment` refuses among them) degrades to an accessible\n * fallback instead of crashing the host.\n *\n * **No `activityTitle`.** Its `data` is two fields of a read-aloud item and\n * carries no title, so the production fallback is the unnamed one. Naming it\n * would mean inventing a title for a panel that never had one.\n */\nexport function PronunciationFeedback(props: PronunciationFeedbackProps) {\n const strings = useLkStrings(props.strings);\n return (\n <ActivityErrorBoundary strings={strings}>\n <PronunciationFeedbackCore {...props} />\n </ActivityErrorBoundary>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/shared/playback-refusal.ts","../src/components/shared/read-grade.ts","../src/components/PronunciationFeedback/PronunciationFeedback.tsx","../src/components/PronunciationFeedback/index.tsx"],"names":["useState","useCallback","validateSpeechAssessment","useLkStrings","useId","useMemo","isDevelopment","ActivitySchemaError","alignReadAloud","useRef","useEffect","localeDirectionOf","jsxs","jsx","Fragment","PronunciationFeedback","ActivityErrorBoundary"],"mappings":"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","file":"chunk-WKOV25NP.cjs","sourcesContent":["'use client';\n\nimport { useCallback, useState } from 'react';\n\n/**\n * Whether the page refused to play the learner's own take, and the handler\n * every element that plays it reports a refusal through.\n *\n * The take is played from a `blob:` URL — the preview of a take not yet sent —\n * or from a link a review minted, and a page can refuse either without a word:\n * a Content-Security-Policy whose `media-src` does not allow `blob:` blocks the\n * load, the element fires `error`, and every control that plays it goes on\n * looking as if it works. So the refusal is decided in one place, by the URL\n * that was refused: a new take is a new URL and starts out playable again, and\n * a refusal an element reports after it was handed another URL cannot mark the\n * new one.\n *\n * `refuse` takes the element, not the URL, and reads the address the element\n * is loading at the moment it fails: an `error` belongs to the source the\n * element holds when it fires, and a closure's URL may already be a render\n * behind it.\n */\nexport function usePlaybackRefusal(url: string | null | undefined): {\n refused: boolean;\n refuse: (element: HTMLMediaElement) => void;\n} {\n const [refusedUrl, setRefusedUrl] = useState<string | null>(null);\n const refuse = useCallback((element: HTMLMediaElement) => {\n const source = element.getAttribute('src');\n if (source !== null) {\n setRefusedUrl(source);\n }\n }, []);\n return { refused: url !== null && url !== undefined && url === refusedUrl, refuse };\n}\n\n/**\n * Whether a rejected `play()` is the page refusing the source, rather than an\n * autoplay policy refusing the gesture. Only the first is the take's to report:\n * an autoplay refusal says nothing about whether the take can be played.\n */\nexport function isSourceRefusal(error: unknown): boolean {\n return (\n typeof error === 'object' &&\n error !== null &&\n (error as { name?: unknown }).name === 'NotSupportedError'\n );\n}\n","'use client';\n\nimport type {\n CriterionScore,\n GradeRecord,\n ReadAloudDimension,\n ScoringDetail,\n ScoringOutcome,\n SpeechAssessment,\n} from '@intellectif/lk-core';\n\n/**\n * The one reader of a grade that arrives from a host.\n *\n * Nothing validates a `GradeRecord`, an `ItemOutcome` or an assess result on\n * the way in: each is the application's, it crosses a network, and a field a\n * backend serialised as `null`, as a string or as an object is the ordinary way\n * to meet one. Every render path used to dereference them in its own way, so\n * every guard added for one shape left its sibling open — `criteria: null`\n * guarded and `criteria: [null]` not, a numeric `score` guarded and a string\n * `maxScore` shown as 8200%, `feedback` as an object taking a whole activity\n * down, `passed: null` dropping a grade from every callback in development and\n * sending an invalid statement in production.\n *\n * So the question \"what did the host send?\" has one answer, given here. The\n * panel, the outcome summary, the announcement, the decision about who shows\n * the score, `onComplete` and the xAPI statement read ONLY what these functions\n * return, and a payload they refuse is shown as could-not-be-graded — never the\n * error boundary, never `NaN`, never a percentage invented from a string.\n *\n * The rules, once:\n *\n * - **A required field is well-formed or the grade is refused.** `score` and\n * `maxScore` are finite numbers, `maxScore` above 0 and `score` between 0 and\n * it; `passed` is a boolean. A numeric string is not a number: `\"100\"` is how\n * a grade out of 100 turned into 8200%, and coercing it would only move the\n * guess somewhere else.\n * - **An optional field is absent when it is `undefined` or `null`** — how a\n * backend writes an absent optional — and otherwise well-formed or dropped.\n * `feedback` that is not a string is no feedback.\n * - **`criteria` keeps each well-formed entry and drops the rest.** Criteria are\n * named rows, each independent: an entry that cannot be read names no row.\n * - **`details` is read whole or not at all.** It is the word marks in order,\n * and a list with one word quietly missing would tell a learner they never\n * read a word they did.\n * - **Nothing here throws.** A payload whose getter throws is a payload that\n * cannot be read.\n */\n\n/** Marks a grade as read by {@link readGrade}. Type-only: it never exists at run time. */\ndeclare const READ: unique symbol;\n\n/**\n * A grade {@link readGrade} has checked: `0 <= score <= maxScore`, `maxScore >\n * 0`, both finite, `passed` a boolean, `feedback` a string or `null`, and\n * `criteria` and `details` (when present) holding only well-formed entries.\n * Still a `GradeRecord`, so it can be handed to anything that takes one — and\n * reading it again gives the same grade.\n */\nexport type ReadGrade = GradeRecord & { readonly [READ]: true };\n\n/** A stored outcome, as a renderer may show it. */\nexport type OutcomeReading =\n /** A grade to show: the outcome's own for `scored`, its `grade` for `graded`. */\n | { kind: 'graded'; status: 'scored' | 'graded'; grade: ReadGrade }\n | { kind: 'deferred' }\n /** `code` is a developer's label: put on an attribute, never shown. */\n | { kind: 'unscorable'; code: string | undefined }\n /** Claimed a grade, or claimed nothing a renderer knows, and could not be read. */\n | { kind: 'unreadable'; status: 'scored' | 'graded' | undefined };\n\n/** An assessor's answer, as a renderer and a statement may use it. */\nexport type AssessReading =\n | {\n status: 'graded';\n /** `null` when what came back cannot be read as a grade. */\n grade: ReadGrade | null;\n /** The evidence when it is an object at all; whether it VALIDATES is the panel's question. */\n assessment: SpeechAssessment | null;\n recognizedText: string | undefined;\n }\n | { status: 'unscorable'; code: string | undefined }\n | { status: 'failed'; retryable: boolean };\n\n/** One dimension row: a whole percentage, or `undefined` for a dimension nobody measured. */\nexport interface DimensionReading {\n dimension: ReadAloudDimension;\n percent: number | undefined;\n}\n\n/**\n * Every dimension a read-aloud grade can weigh, in the order a learner reads\n * them: what was said, how it flowed, how much of it was there, and how it was\n * pitched. Fixed rather than derived from the evidence, so a dimension the\n * engine did not measure is reported as unmeasured instead of vanishing.\n */\nconst DIMENSIONS: readonly ReadAloudDimension[] = [\n 'accuracy',\n 'fluency',\n 'completeness',\n 'prosody',\n];\n\nconst OUTCOMES: readonly ScoringOutcome[] = [\n 'correct',\n 'incorrect',\n 'correct-omission',\n 'incorrect-omission',\n];\n\n/**\n * How far past its own maximum a score may sit and still be read as that\n * maximum. A grader that sums weighted parts lands on `1.0000000000000002`\n * for a perfect take as readily as on `1`, and \"could not be graded\" is the\n * wrong thing to tell the learner who earned it. Far below any difference a\n * whole percentage can show.\n */\nconst OVERSHOOT = 1e-9;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === 'number' && Number.isFinite(value);\n}\n\n/** An optional field a backend left out, written either way it writes one. */\nfunction isAbsent(value: unknown): value is null | undefined {\n return value === undefined || value === null;\n}\n\n/** A score on `0..max`, a hair of overshoot read as `max`; `null` for anything else. */\nfunction withinMax(score: unknown, max: number): number | null {\n if (!isFiniteNumber(score) || score < 0) {\n return null;\n }\n if (score <= max) {\n return score;\n }\n return score - max <= max * OVERSHOOT ? max : null;\n}\n\n/** A learner's or a reference response: a string, or strings. */\nfunction isResponse(value: unknown): value is string | string[] {\n return (\n typeof value === 'string' ||\n (Array.isArray(value) && value.every((entry) => typeof entry === 'string'))\n );\n}\n\n/** Runs a read that touches a host's object, whose getters may throw. */\nfunction guarded<T>(read: () => T, refused: T): T {\n try {\n return read();\n } catch {\n return refused;\n }\n}\n\nfunction readCriterion(value: unknown): CriterionScore | null {\n if (!isRecord(value) || typeof value.name !== 'string') {\n return null;\n }\n const { maxScore, notApplicable } = value;\n if (!isAbsent(maxScore) && !(isFiniteNumber(maxScore) && maxScore > 0)) {\n return null;\n }\n if (!isAbsent(notApplicable) && typeof notApplicable !== 'boolean') {\n return null;\n }\n // `CriterionScore.maxScore` defaults to 1, the SDK's scaled convention.\n const score = isAbsent(value.score) ? undefined : withinMax(value.score, maxScore ?? 1);\n if (score === null) {\n return null;\n }\n return {\n name: value.name,\n ...(score !== undefined ? { score } : {}),\n ...(!isAbsent(maxScore) ? { maxScore } : {}),\n ...(notApplicable === true ? { notApplicable } : {}),\n };\n}\n\nfunction readDetail(value: unknown): ScoringDetail | null {\n if (!isRecord(value)) {\n return null;\n }\n const { itemId, correct, outcome, learnerResponse, correctResponse, weight, score } = value;\n if (\n typeof itemId !== 'string' ||\n typeof correct !== 'boolean' ||\n !isResponse(learnerResponse) ||\n !isResponse(correctResponse)\n ) {\n return null;\n }\n const checkedOutcome = OUTCOMES.find((known) => known === outcome);\n if (!isAbsent(outcome) && checkedOutcome === undefined) {\n return null;\n }\n if (!isAbsent(weight) && !isFiniteNumber(weight)) {\n return null;\n }\n // A detail's own score is a fraction of 1.\n const checkedScore = isAbsent(score) ? undefined : withinMax(score, 1);\n if (checkedScore === null) {\n return null;\n }\n return {\n itemId,\n correct,\n learnerResponse,\n correctResponse,\n ...(checkedOutcome !== undefined ? { outcome: checkedOutcome } : {}),\n ...(!isAbsent(weight) ? { weight } : {}),\n ...(checkedScore !== undefined ? { score: checkedScore } : {}),\n };\n}\n\nfunction readDetails(value: unknown): ScoringDetail[] | undefined {\n if (!Array.isArray(value)) {\n return undefined;\n }\n const details: ScoringDetail[] = [];\n for (const entry of value) {\n const detail = readDetail(entry);\n if (detail === null) {\n return undefined;\n }\n details.push(detail);\n }\n return details;\n}\n\n/**\n * A host's grade as a checked copy, or `null` when it carries no grade that can\n * be shown or reported. See the module notes for the rules.\n */\nexport function readGrade(value: unknown): ReadGrade | null {\n return guarded(() => {\n if (!isRecord(value)) {\n return null;\n }\n const { maxScore, passed } = value;\n if (!isFiniteNumber(maxScore) || maxScore <= 0 || typeof passed !== 'boolean') {\n return null;\n }\n const score = withinMax(value.score, maxScore);\n if (score === null) {\n return null;\n }\n const criteria = Array.isArray(value.criteria)\n ? value.criteria.flatMap((entry) => {\n const criterion = readCriterion(entry);\n return criterion === null ? [] : [criterion];\n })\n : undefined;\n const details = readDetails(value.details);\n const grade: GradeRecord = {\n score,\n maxScore,\n passed,\n feedback: typeof value.feedback === 'string' ? value.feedback : null,\n ...(criteria !== undefined ? { criteria } : {}),\n ...(details !== undefined ? { details } : {}),\n };\n return grade as ReadGrade;\n }, null);\n}\n\n/** A read grade as a fraction of 1: in `0..1`, because the reader made it so. */\nexport function fractionOfGrade(grade: ReadGrade): number {\n return grade.score / grade.maxScore;\n}\n\n/** A read grade as a whole percentage: in `0..100`, because the reader made it so. */\nexport function percentOfGrade(grade: ReadGrade): number {\n return Math.round(fractionOfGrade(grade) * 100);\n}\n\n/**\n * A stored outcome as a renderer may show it, or `undefined` for none —\n * `null` included, which is how a backend writes an absent optional.\n *\n * A `graded` outcome is read through its `grade`, the record\n * `outcomeFromGrade` mirrors onto it, so the summary and the panel beside it\n * can never show two different numbers; and it must be well-formed as a whole,\n * its own `score`, `maxScore` and `passed` included — a payload with a corrupt\n * copy of the grade is not one to pick a side of.\n */\nexport function readOutcome(value: unknown): OutcomeReading | undefined {\n if (isAbsent(value)) {\n return undefined;\n }\n return guarded(\n (): OutcomeReading => {\n if (!isRecord(value)) {\n return { kind: 'unreadable', status: undefined };\n }\n switch (value.status) {\n case 'deferred':\n return { kind: 'deferred' };\n case 'unscorable':\n return {\n kind: 'unscorable',\n code: typeof value.code === 'string' ? value.code : undefined,\n };\n case 'scored': {\n const grade = readGrade(value);\n return grade === null\n ? { kind: 'unreadable', status: 'scored' }\n : { kind: 'graded', status: 'scored', grade };\n }\n case 'graded': {\n const grade = readGrade(value.grade);\n return grade === null || readGrade(value) === null\n ? { kind: 'unreadable', status: 'graded' }\n : { kind: 'graded', status: 'graded', grade };\n }\n default:\n return { kind: 'unreadable', status: undefined };\n }\n },\n { kind: 'unreadable', status: undefined },\n );\n}\n\n/**\n * An assessor's answer as a renderer and a statement may use it.\n *\n * `failed` and `unscorable` need little: a `retryable` that is not `true`\n * offers no retry, which never spends an application's money on a guess, and a\n * `code` that is not a string is no code. Everything else — a `graded` result,\n * and anything that is not an object or names no status this component knows —\n * is read as a judgement: its grade when one can be read, its evidence when it\n * is an object. A judgement with neither is shown as could-not-be-graded.\n */\nexport function readAssessResult(value: unknown): AssessReading {\n const nothing: AssessReading = {\n status: 'graded',\n grade: null,\n assessment: null,\n recognizedText: undefined,\n };\n return guarded((): AssessReading => {\n if (!isRecord(value)) {\n return nothing;\n }\n if (value.status === 'failed') {\n return { status: 'failed', retryable: value.retryable === true };\n }\n if (value.status === 'unscorable') {\n return {\n status: 'unscorable',\n code: typeof value.code === 'string' ? value.code : undefined,\n };\n }\n if (value.status !== 'graded') {\n return nothing;\n }\n const assessment = readEvidence(value.assessment);\n const recognizedText = guarded(\n () =>\n typeof assessment?.recognizedText === 'string' ? assessment.recognizedText : undefined,\n undefined,\n );\n return { status: 'graded', grade: readGrade(value.grade), assessment, recognizedText };\n }, nothing);\n}\n\n/**\n * Evidence worth handing to the panel: an object. Whether it validates is the\n * panel's to decide, because what a refusal costs differs by mode.\n */\nexport function readEvidence(value: unknown): SpeechAssessment | null {\n return isRecord(value) ? (value as unknown as SpeechAssessment) : null;\n}\n\n/** One criterion's whole percentage of its own maximum, or `undefined` when it carries none. */\nfunction percentOfCriterion(criterion: CriterionScore): number | undefined {\n if (criterion.notApplicable === true || criterion.score === undefined) {\n return undefined;\n }\n return Math.round((criterion.score / (criterion.maxScore ?? 1)) * 100);\n}\n\n/**\n * The dimension rows, from one source for the whole set and never a mix: the\n * grade's criteria when it has any it can read, and the evidence's own scores\n * otherwise. A dimension pulled out of the evidence and set beside graded ones\n * would read as if it had counted towards the grade.\n *\n * The evidence is read as defensively as the grade: in production the panel\n * shows these rows even for evidence the validator refused, which can carry\n * anything at all under `scores`. `scale` is 100 by schema, so an evidence\n * score is already a percentage — and one outside `0..100` is not one.\n */\nexport function readDimensions(\n assessment: unknown,\n grade: ReadGrade | null | undefined,\n): DimensionReading[] {\n const criteria = grade?.criteria ?? [];\n if (criteria.length > 0) {\n return DIMENSIONS.map((dimension) => {\n const criterion = criteria.find((entry) => entry.name === dimension);\n return {\n dimension,\n percent: criterion === undefined ? undefined : percentOfCriterion(criterion),\n };\n });\n }\n const scores = guarded(() => (isRecord(assessment) ? assessment.scores : undefined), undefined);\n return DIMENSIONS.map((dimension) => {\n const score = withinMax(\n guarded(() => (isRecord(scores) ? scores[dimension] : undefined), undefined),\n 100,\n );\n // Rounded rather than reformatted: the engine's own number is what was graded.\n return { dimension, percent: score === null ? undefined : Math.round(score) };\n });\n}\n","'use client';\n\nimport {\n ActivitySchemaError,\n alignReadAloud,\n type GradeRecord,\n type ReadAloudData,\n type ReadAloudWordAlignment,\n type SpeechAssessment,\n type SpeechPhoneme,\n type SpeechWord,\n type ThemeTokens,\n type ValidationResult,\n validateSpeechAssessment,\n} from '@intellectif/lk-core';\nimport { type CSSProperties, useEffect, useId, useMemo, useRef, useState } from 'react';\nimport { localeDirectionOf } from '../../i18n/direction.js';\nimport { useLkStrings } from '../../i18n/LkIntlProvider.js';\nimport type { LkStrings, LkStringsOverride } from '../../i18n/strings.js';\nimport { isDevelopment } from '../_internal.js';\nimport { isSourceRefusal, usePlaybackRefusal } from '../shared/playback-refusal.js';\nimport { percentOfGrade, readDimensions, readGrade } from '../shared/read-grade.js';\n\n/**\n * Present for assistive technology, invisible on screen. Inline rather than\n * left to the optional skin, for the reason `<Dictation>` gives: the per-word\n * sentences are the marks' only channel for a screen reader, and a page that\n * does not load the skin would otherwise show every one of them beside its\n * word. Exported so `<ReadAloud>`, whose review fallback renders the same\n * marks from stored details, carries one definition rather than a copy.\n */\nexport const VISUALLY_HIDDEN: CSSProperties = {\n position: 'absolute',\n width: 1,\n height: 1,\n margin: -1,\n padding: 0,\n overflow: 'hidden',\n clip: 'rect(0 0 0 0)',\n clipPath: 'inset(50%)',\n whiteSpace: 'nowrap',\n border: 0,\n};\n\n/** The four marking states, in the order the legend lists them. */\nconst LEGEND_STATES: readonly ReadAloudWordAlignment['state'][] = [\n 'correct',\n 'mispronounced',\n 'omitted',\n 'inserted',\n];\n\nexport interface PronunciationFeedbackProps {\n /**\n * The item's reading and its language. Only these two fields, because they\n * are the only ones a mark depends on — everything else about the activity\n * belongs to whoever rendered it.\n */\n data: Pick<ReadAloudData, 'referenceText' | 'locale'>;\n /**\n * The assessor's evidence. Checked with `validateSpeechAssessment` before it\n * is aligned: see the note on this component about what a bad one costs.\n */\n assessment: SpeechAssessment;\n /**\n * The grade the evidence produced, when one exists. Its `criteria` are what\n * the dimensions are read from, because they are the numbers the learner was\n * actually graded on. A grade that cannot be read — a score that is not a\n * number between 0 and its maximum, a `passed` that is not a boolean — is\n * shown as could-not-be-graded, never as a percentage made up from it.\n */\n grade?: GradeRecord;\n /**\n * The learner's own take, playable. With it, each word that carries timings\n * gets a button that plays just that word. A take the page refuses to play —\n * a `blob:` URL under a Content-Security-Policy whose `media-src` does not\n * allow one, most often — offers no such button, and the panel says the take\n * cannot be played here.\n */\n audioUrl?: string;\n /**\n * Confidence above which a break note is shown, 0..1. **No default**: how\n * confident an engine has to be before a pause is worth telling a learner\n * about is a calibration, and the SDK has no calibrated answer. Without it no\n * break note is shown at all.\n */\n breakThreshold?: number;\n /** The same, for the monotone note read off `assessment.prosody`. */\n monotoneThreshold?: number;\n /**\n * BCP 47 tag stamped as `lang` on the root: the INTERFACE language, the one\n * this component's own sentences are written in. It is not `data.locale`,\n * which is the language of the reading and is put on the words themselves.\n */\n locale?: string;\n /** Per-instance token overrides, applied as inline CSS vars on the root. */\n theme?: Partial<ThemeTokens>;\n /** Overrides the SDK's chrome text for this panel. See {@link LkIntlProvider}. */\n strings?: LkStringsOverride;\n}\n\n/**\n * What the validator says about evidence that may not even be readable. Its\n * cross-field rules read the value directly, so a getter that throws escapes\n * it — and evidence that cannot be read is evidence refused, not a reason to\n * take the grade beside it down.\n */\nfunction checkEvidence(assessment: unknown): ValidationResult<SpeechAssessment> {\n try {\n return validateSpeechAssessment(assessment);\n } catch {\n return {\n success: false,\n errors: [{ path: [], message: 'The assessment could not be read.', code: 'unreadable' }],\n };\n }\n}\n\n/** Whether a word carries anything a disclosure would have to show. */\nfunction hasDetail(word: SpeechWord | undefined): word is SpeechWord {\n if (word === undefined) {\n return false;\n }\n return (\n word.accuracy !== undefined ||\n (word.syllables !== undefined && word.syllables.length > 0) ||\n (word.phonemes !== undefined && word.phonemes.length > 0) ||\n word.breaks !== undefined ||\n (typeof word.startMs === 'number' && typeof word.durationMs === 'number')\n );\n}\n\n/** A confidence that clears the caller's threshold. No threshold, no note. */\nfunction past(confidence: number | undefined, threshold: number | undefined): boolean {\n return (\n threshold !== undefined &&\n typeof confidence === 'number' &&\n Number.isFinite(confidence) &&\n confidence > threshold\n );\n}\n\n/** One phoneme, named by its symbol or — when the engine named none — by its place. */\nfunction phonemeLabel(phoneme: SpeechPhoneme, index: number, s: LkStrings): string {\n return phoneme.symbol ?? s.pronunciationPhonemePosition(index + 1);\n}\n\n/**\n * What a screen reader hears for one marked word — the marks' only channel for\n * assistive technology, since the glyph and the decoration are both hidden from\n * it. Exported because `<ReadAloud>`'s review fallback marks the same four\n * states from stored details, and a second copy of these four sentences would\n * be a second thing to translate.\n *\n * Branches on `state` and **never** on `heard === ''`: an inserted word whose\n * text normalises to nothing carries the empty string too, and would otherwise\n * be announced as an omission.\n */\nexport function markSentence(entry: ReadAloudWordAlignment, s: LkStrings): string {\n switch (entry.state) {\n case 'correct':\n return s.pronunciationWordCorrect(entry.reference);\n case 'mispronounced':\n return s.pronunciationWordMispronounced(entry.reference);\n case 'omitted':\n return s.pronunciationWordOmitted(entry.reference);\n default:\n return s.pronunciationWordInserted(entry.heard);\n }\n}\n\n/**\n * The per-word marks of a read-aloud take, plus the dimensions they were\n * graded on.\n *\n * **A bad assessment never destroys a good grade.** `alignReadAloud` throws a\n * `TypeError` for evidence `validateSpeechAssessment` refuses, so this\n * component runs the validator first. In development the refusal is thrown as\n * an `ActivitySchemaError`, which is the package's dev-error convention and\n * puts the problem in front of whoever wired the adapter up. In production the\n * dimensions and the grade are rendered and the word list is left out — a\n * learner who earned 82% should see 82%, not \"this activity could not be\n * displayed\" from an error boundary.\n *\n * **Nor does a bad grade take the evidence down.** `grade` is read, not\n * trusted: a score that is not a number between 0 and its maximum, or a\n * `passed` that is not a boolean, is shown as could-not-be-graded beside the\n * dimensions and the marks, and criteria that cannot be read name no dimension.\n *\n * There is **no `renderMode`**: nothing here submits, grades or reveals an\n * answer key. A read-aloud item has none, and the marks exist only once a\n * server has graded the take, so there is no mode in which they must be\n * withheld.\n *\n * ```tsx\n * <PronunciationFeedback\n * data={item}\n * assessment={assessment}\n * grade={grade}\n * audioUrl={takeUrl}\n * breakThreshold={0.75}\n * monotoneThreshold={0.6}\n * />\n * ```\n */\nexport function PronunciationFeedback({\n data,\n assessment,\n grade,\n audioUrl,\n breakThreshold,\n monotoneThreshold,\n locale,\n theme,\n strings,\n}: PronunciationFeedbackProps) {\n const s = useLkStrings(strings);\n const ids = useId();\n const [openWord, setOpenWord] = useState<number | null>(null);\n\n const checked = useMemo(() => checkEvidence(assessment), [assessment]);\n\n const devError = useMemo(\n () =>\n isDevelopment() && !checked.success\n ? new ActivitySchemaError('read-aloud', checked.errors)\n : null,\n [checked],\n );\n\n // The checked copy, never the argument, for the same reason lk-core aligns\n // from it: a property getter cannot answer the validator one word and the\n // aligner another.\n const words = useMemo<ReadAloudWordAlignment[] | null>(\n () => (checked.success ? alignReadAloud(data, checked.data) : null),\n [checked, data],\n );\n\n // The grade as the one reader of a host's grade reads it: `undefined` when\n // none was given, and `null` when one was and cannot be shown. Everything\n // below that shows a number reads this and the dimension rows, never `grade`.\n const reading = useMemo(\n () => (grade === undefined || grade === null ? undefined : readGrade(grade)),\n [grade],\n );\n const dimensions = useMemo(() => readDimensions(assessment, reading), [assessment, reading]);\n\n // The take, for the per-word play buttons. A ref and an effect, never a read\n // during render: this component server-renders like every other one here.\n const audioRef = useRef<HTMLAudioElement>(null);\n const stopRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const playback = usePlaybackRefusal(audioUrl);\n // A take the page refused is offered to no button: pressed, each would do\n // nothing, which is the silent failure the note below replaces.\n const playable = audioUrl !== undefined && !playback.refused;\n useEffect(\n () => () => {\n if (stopRef.current !== null) {\n clearTimeout(stopRef.current);\n }\n },\n [],\n );\n\n // All hooks are called before this throw, so hook order stays stable.\n if (devError) {\n throw devError;\n }\n\n /** Plays one word out of the take, and stops at the end of it. */\n const playWord = (startMs: number, durationMs: number): void => {\n const element = audioRef.current;\n if (element === null) {\n return;\n }\n if (stopRef.current !== null) {\n clearTimeout(stopRef.current);\n }\n element.currentTime = startMs / 1000;\n try {\n void element.play().catch((error: unknown) => {\n // An autoplay refusal is not this component's to report; a source the\n // page will not load is, and the element's own `error` may not have\n // fired yet for an engine that loads nothing until asked.\n if (isSourceRefusal(error)) {\n playback.refuse(element);\n }\n });\n } catch {\n /* an engine with no media stack at all; the button simply does nothing */\n }\n stopRef.current = setTimeout(() => {\n stopRef.current = null;\n element.pause();\n }, durationMs);\n };\n\n // The reading's own language and the direction its tag names, put on the\n // words and on nothing else: the sentences beside them are interface text.\n // No `_`→`-` normalisation, unlike `<Dictation>` — `ReadAloudData.locale` is\n // canonical by schema, so there is nothing to normalise.\n const contentLang = typeof data.locale === 'string' ? data.locale : undefined;\n const contentDir = localeDirectionOf(data.locale);\n\n const alphabet = checked.success ? checked.data.phonemeAlphabet : undefined;\n const monotone = checked.success ? checked.data.prosody?.monotoneConfidence : undefined;\n // Read through `at`, not through an index: `wordIndex` belongs to a public\n // type a caller may have built by hand, and it is allowed to point nowhere.\n const evidenceWords: readonly SpeechWord[] = checked.success ? checked.data.words : [];\n\n return (\n <section\n className=\"lk-pf\"\n aria-label={s.pronunciationFeedbackLabel}\n lang={locale}\n style={theme as CSSProperties | undefined}\n >\n {reading !== undefined ? (\n // `.lk-pf-grade` is load-bearing beyond the skin: `<ReadAloud>` looks\n // for it after the commit to decide whether it must render the score\n // itself, so a grade is never lost between the two components. It\n // hands this panel only a grade it has already read, so the block it\n // finds always carries the score.\n //\n // `data-passed` only where there is a verdict: a grade that could not\n // be read has none, and styling it as a fail would invent one.\n <div\n className=\"lk-pf-grade\"\n {...(reading !== null ? { 'data-passed': String(reading.passed) } : {})}\n >\n <p className=\"lk-pf-score\">\n {reading === null\n ? s.couldNotBeGraded\n : s.scoreAnnouncement(percentOfGrade(reading), reading.passed)}\n </p>\n {/* The grader's words, isolated: their direction is their own, so an\n English comment in an Arabic interface keeps its full stop at its\n end. Their language is not guessed — feedback may be written in\n either the interface's language or the reading's. */}\n {reading?.feedback ? (\n <p className=\"lk-pf-grade-feedback\" dir=\"auto\">\n {reading.feedback}\n </p>\n ) : null}\n </div>\n ) : null}\n\n <dl className=\"lk-pf-dimensions\">\n {dimensions.map(({ dimension, percent }) => (\n <div className=\"lk-pf-dimension\" key={dimension} data-dimension={dimension}>\n <dt className=\"lk-pf-dimension-name\">{s.pronunciationDimension(dimension)}</dt>\n {/* An absent score is NEVER a 0: a dimension nobody measured and a\n dimension measured at nothing are different findings, and only\n one of them is the learner's. */}\n <dd className=\"lk-pf-dimension-score\">\n {percent === undefined ? s.pronunciationNotAssessed : `${percent}%`}\n </dd>\n </div>\n ))}\n </dl>\n\n {words !== null ? (\n <>\n {/* The list's name and the hidden sentences are interface text and\n keep the interface language; only the words carry the reading's.\n Its direction is the reading's, never resolved from the list's own\n text: the first strong character there is a hidden sentence. */}\n <ol className=\"lk-pf-words\" aria-label={s.pronunciationWordsLabel} dir={contentDir}>\n {words.map((entry, index) => {\n const sentence = markSentence(entry, s);\n const shown = entry.state === 'inserted' ? entry.heard : entry.reference;\n const word =\n entry.wordIndex === undefined ? undefined : evidenceWords.at(entry.wordIndex);\n const open = openWord === index;\n const panelId = `${ids}-w${index}`;\n return (\n <li\n // biome-ignore lint/suspicious/noArrayIndexKey: alignment order is the identity; words repeat\n key={index}\n className=\"lk-pf-word\"\n data-state={entry.state}\n >\n {/* The state's only channel for assistive technology, and\n exactly one channel: the same sentence as a `title` is an\n accessible description, which a screen reader reads\n straight after the name it duplicates. */}\n <span className=\"lk-visually-hidden\" style={VISUALLY_HIDDEN}>\n {sentence}\n </span>\n {/* Decoration: the glyph the skin draws and the word itself.\n Hidden from assistive technology, which already has the\n sentence above — and the glyph is never the only channel. */}\n <span\n className=\"lk-pf-word-text\"\n aria-hidden=\"true\"\n dir={contentDir ?? 'auto'}\n lang={contentLang}\n >\n {shown}\n </span>\n {hasDetail(word) ? (\n <>\n <button\n type=\"button\"\n className=\"lk-pf-word-toggle\"\n aria-expanded={open}\n aria-controls={panelId}\n onClick={() => setOpenWord(open ? null : index)}\n >\n {s.pronunciationWordDetails(shown)}\n </button>\n {open ? (\n <div id={panelId} className=\"lk-pf-word-detail\">\n <dl className=\"lk-pf-word-facts\">\n <dt>{s.pronunciationDimension('accuracy')}</dt>\n <dd>\n {word.accuracy === undefined\n ? s.pronunciationNotAssessed\n : `${Math.round(word.accuracy)}%`}\n </dd>\n {word.syllables !== undefined && word.syllables.length > 0 ? (\n <>\n <dt>{s.pronunciationSyllables}</dt>\n <dd>\n <ul className=\"lk-pf-syllables\">\n {word.syllables.map((syllable, position) => (\n <li\n // biome-ignore lint/suspicious/noArrayIndexKey: syllables are positional and repeat within a word\n key={position}\n dir={contentDir ?? 'auto'}\n lang={contentLang}\n >\n {syllable.grapheme === undefined\n ? syllable.text\n : s.pronunciationSyllableSpelling(\n syllable.text,\n syllable.grapheme,\n )}\n </li>\n ))}\n </ul>\n </dd>\n </>\n ) : null}\n {word.phonemes !== undefined && word.phonemes.length > 0 ? (\n <>\n <dt>{s.pronunciationPhonemes}</dt>\n <dd>\n <ul className=\"lk-pf-phonemes\">\n {word.phonemes.map((phoneme, position) => (\n <li\n // biome-ignore lint/suspicious/noArrayIndexKey: a word may sound the same phoneme twice\n key={position}\n className=\"lk-pf-phoneme\"\n >\n <span className=\"lk-pf-phoneme-symbol\">\n {phonemeLabel(phoneme, position, s)}\n </span>\n {phoneme.heardAs !== undefined &&\n phoneme.heardAs.length > 0 ? (\n <>\n <span className=\"lk-pf-heard-label\">\n {s.pronunciationHeardAs}\n </span>\n <ul className=\"lk-pf-heard-as\">\n {phoneme.heardAs.map((candidate, rank) => (\n <li\n // biome-ignore lint/suspicious/noArrayIndexKey: candidates are ranked and a symbol may repeat\n key={rank}\n >\n {candidate.symbol}\n </li>\n ))}\n </ul>\n </>\n ) : null}\n </li>\n ))}\n </ul>\n </dd>\n </>\n ) : null}\n </dl>\n {playable &&\n typeof word.startMs === 'number' &&\n typeof word.durationMs === 'number' ? (\n <button\n type=\"button\"\n className=\"lk-pf-word-play\"\n onClick={() =>\n playWord(word.startMs as number, word.durationMs as number)\n }\n >\n {s.pronunciationPlayWord(shown)}\n </button>\n ) : null}\n {past(word.breaks?.unexpected, breakThreshold) ? (\n <p className=\"lk-pf-break\" data-break=\"unexpected\">\n {s.pronunciationBreakUnexpected}\n </p>\n ) : null}\n {past(word.breaks?.missing, breakThreshold) ? (\n <p className=\"lk-pf-break\" data-break=\"missing\">\n {s.pronunciationBreakMissing}\n </p>\n ) : null}\n </div>\n ) : null}\n </>\n ) : null}\n </li>\n );\n })}\n </ol>\n <ul className=\"lk-pf-legend\">\n {LEGEND_STATES.map((state) => (\n <li key={state} data-state={state}>\n {s.pronunciationLegend(state)}\n </li>\n ))}\n </ul>\n {/* Only where there are symbols to explain, and only for the alphabet\n this note names. An engine that reported another one, or none at\n all, gets no note rather than a wrong one. */}\n {alphabet === 'ipa' ? <p className=\"lk-pf-alphabet\">{s.pronunciationIpaNote}</p> : null}\n </>\n ) : null}\n\n {past(monotone, monotoneThreshold) ? (\n <p className=\"lk-pf-monotone\" role=\"note\">\n {s.pronunciationMonotone}\n </p>\n ) : null}\n\n {audioUrl === undefined ? null : playback.refused ? (\n <p className=\"lk-pf-audio-unavailable\" role=\"note\">\n {s.readAloudPlaybackUnavailable}\n </p>\n ) : (\n // biome-ignore lint/a11y/useMediaCaption: the learner's own take has no caption track to offer, and this element is never played as content — it carries no controls and exists only so one word can be replayed from a button that names it\n <audio\n ref={audioRef}\n className=\"lk-pf-audio\"\n src={audioUrl}\n preload=\"metadata\"\n onError={(event) => playback.refuse(event.currentTarget)}\n />\n )}\n </section>\n );\n}\n","'use client';\n\nimport { useLkStrings } from '../../i18n/LkIntlProvider.js';\nimport { ActivityErrorBoundary } from '../ActivityErrorBoundary.js';\nimport {\n PronunciationFeedback as PronunciationFeedbackCore,\n type PronunciationFeedbackProps,\n} from './PronunciationFeedback.js';\n\nexport type { PronunciationFeedbackProps } from './PronunciationFeedback.js';\n\n/**\n * Public pronunciation-feedback panel: the core wrapped in\n * `ActivityErrorBoundary` so a render failure (the dev throw for evidence\n * `validateSpeechAssessment` refuses among them) degrades to an accessible\n * fallback instead of crashing the host.\n *\n * **No `activityTitle`.** Its `data` is two fields of a read-aloud item and\n * carries no title, so the production fallback is the unnamed one. Naming it\n * would mean inventing a title for a panel that never had one.\n */\nexport function PronunciationFeedback(props: PronunciationFeedbackProps) {\n const strings = useLkStrings(props.strings);\n return (\n <ActivityErrorBoundary strings={strings}>\n <PronunciationFeedbackCore {...props} />\n </ActivityErrorBoundary>\n );\n}\n"]}
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
|
|
4
4
|
var chunkOD65OZIW_cjs = require('./chunk-OD65OZIW.cjs');
|
|
5
5
|
var chunkBRPEB43C_cjs = require('./chunk-BRPEB43C.cjs');
|
|
6
|
-
var
|
|
7
|
-
var
|
|
6
|
+
var chunk53YOZOGN_cjs = require('./chunk-53YOZOGN.cjs');
|
|
7
|
+
var chunkFKGUKFC7_cjs = require('./chunk-FKGUKFC7.cjs');
|
|
8
8
|
var chunkXOR4MPEN_cjs = require('./chunk-XOR4MPEN.cjs');
|
|
9
|
-
var
|
|
9
|
+
var chunkZ6TVOAO5_cjs = require('./chunk-Z6TVOAO5.cjs');
|
|
10
10
|
var lkCore = require('@intellectif/lk-core');
|
|
11
11
|
var react = require('react');
|
|
12
12
|
var jsxRuntime = require('react/jsx-runtime');
|
|
@@ -312,10 +312,10 @@ function Dictation({
|
|
|
312
312
|
}) {
|
|
313
313
|
const isExam = renderMode === "exam";
|
|
314
314
|
const isReview = renderMode === "review";
|
|
315
|
-
const s =
|
|
315
|
+
const s = chunkZ6TVOAO5_cjs.useLkStrings(strings);
|
|
316
316
|
const hasKey = typeof data.transcript === "string";
|
|
317
317
|
const devError = react.useMemo(() => {
|
|
318
|
-
if (!
|
|
318
|
+
if (!chunk53YOZOGN_cjs.isDevelopment()) {
|
|
319
319
|
return null;
|
|
320
320
|
}
|
|
321
321
|
if (data.redacted === true) {
|
|
@@ -494,9 +494,9 @@ function Dictation({
|
|
|
494
494
|
complete();
|
|
495
495
|
const timeSpent = getTimeSpent();
|
|
496
496
|
const xapiStatement = lkCore.xAPIBuilder.buildAnsweredStatement({
|
|
497
|
-
actor:
|
|
497
|
+
actor: chunk53YOZOGN_cjs.ANONYMOUS_ACTOR,
|
|
498
498
|
object: {
|
|
499
|
-
id:
|
|
499
|
+
id: chunk53YOZOGN_cjs.objectIdFor(data.id),
|
|
500
500
|
name: { [data.locale ?? "en-US"]: data.title },
|
|
501
501
|
...lkCore.xapiDefinitionFor(data)
|
|
502
502
|
},
|
|
@@ -599,7 +599,7 @@ function Dictation({
|
|
|
599
599
|
data.media !== void 0 ? /* @__PURE__ */ jsxRuntime.jsxs("fieldset", { className: "lk-dc-recording", children: [
|
|
600
600
|
/* @__PURE__ */ jsxRuntime.jsx("legend", { className: "lk-dc-recording-label", children: s.dictationRecording }),
|
|
601
601
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
602
|
-
|
|
602
|
+
chunkFKGUKFC7_cjs.ActivityMedia,
|
|
603
603
|
{
|
|
604
604
|
media: data.media,
|
|
605
605
|
renderMode,
|
|
@@ -616,7 +616,7 @@ function Dictation({
|
|
|
616
616
|
slowMedia !== void 0 ? /* @__PURE__ */ jsxRuntime.jsxs("fieldset", { className: "lk-dc-recording", "data-slow": "true", children: [
|
|
617
617
|
/* @__PURE__ */ jsxRuntime.jsx("legend", { className: "lk-dc-recording-label", children: s.dictationSlowRecording }),
|
|
618
618
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
619
|
-
|
|
619
|
+
chunkFKGUKFC7_cjs.ActivityMedia,
|
|
620
620
|
{
|
|
621
621
|
media: slowMedia,
|
|
622
622
|
renderMode,
|
|
@@ -756,10 +756,10 @@ function Dictation({
|
|
|
756
756
|
);
|
|
757
757
|
}
|
|
758
758
|
function Dictation2(props) {
|
|
759
|
-
const strings =
|
|
760
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
759
|
+
const strings = chunkZ6TVOAO5_cjs.useLkStrings(props.strings);
|
|
760
|
+
return /* @__PURE__ */ jsxRuntime.jsx(chunk53YOZOGN_cjs.ActivityErrorBoundary, { activityTitle: props.data?.title, strings, children: /* @__PURE__ */ jsxRuntime.jsx(Dictation, { ...props }) });
|
|
761
761
|
}
|
|
762
762
|
|
|
763
763
|
exports.Dictation = Dictation2;
|
|
764
|
-
//# sourceMappingURL=chunk-
|
|
765
|
-
//# sourceMappingURL=chunk-
|
|
764
|
+
//# sourceMappingURL=chunk-XMJE34FY.cjs.map
|
|
765
|
+
//# sourceMappingURL=chunk-XMJE34FY.cjs.map
|