@pie-element/mc-populated-blank 0.2.13 → 0.3.0-next.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/configure.js +2 -0
- package/dist/author/index.d.ts +0 -1
- package/dist/author/index.js +1235 -1092
- package/dist/author/index.js.map +1 -1
- package/dist/browser/author/index.js +50 -0
- package/dist/browser/author/index.js.map +1 -0
- package/dist/browser/client-BAfWqkS6.js +2358 -0
- package/dist/browser/client-BAfWqkS6.js.map +1 -0
- package/dist/browser/controller/index.js +219 -0
- package/dist/browser/controller/index.js.map +1 -0
- package/dist/browser/delivery/index.js +1059 -0
- package/dist/browser/delivery/index.js.map +1 -0
- package/dist/browser/layoutLimits-ATKOwLHb.js +42 -0
- package/dist/browser/layoutLimits-ATKOwLHb.js.map +1 -0
- package/dist/browser/print/index.js +125 -0
- package/dist/browser/print/index.js.map +1 -0
- package/dist/controller/defaults.d.ts +0 -2
- package/dist/controller/index.d.ts +0 -3
- package/dist/controller/index.js +0 -2
- package/dist/controller/index.js.map +1 -1
- package/dist/delivery/computeAudioMode.d.ts +0 -1
- package/dist/delivery/computeChoiceCorrectness.d.ts +0 -1
- package/dist/delivery/computeDisplayState.d.ts +0 -1
- package/dist/delivery/computeLayoutProfile.d.ts +0 -1
- package/dist/delivery/computeLayoutStyle.d.ts +0 -2
- package/dist/delivery/index.d.ts +0 -1
- package/dist/delivery/index.js +1527 -1584
- package/dist/delivery/index.js.map +1 -1
- package/dist/delivery/variant-css-map.d.ts +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.iife.d.ts +0 -3
- package/dist/index.iife.js +14 -15
- package/dist/index.js +1527 -1584
- package/dist/index.js.map +1 -1
- package/dist/print/index.d.ts +0 -1
- package/dist/print/index.js +1414 -1270
- package/dist/print/index.js.map +1 -1
- package/dist/runtime-support.d.ts +12 -0
- package/dist/runtime-support.js +14 -0
- package/dist/runtime-support.js.map +1 -0
- package/dist/shared/layoutLimits.d.ts +0 -1
- package/dist/shared/types.d.ts +9 -2
- package/module/print.js +2312 -0
- package/module/print.js.map +1 -0
- package/package.json +40 -8
- package/dist/author/index.d.ts.map +0 -1
- package/dist/controller/defaults.d.ts.map +0 -1
- package/dist/controller/index.d.ts.map +0 -1
- package/dist/delivery/computeAudioMode.d.ts.map +0 -1
- package/dist/delivery/computeChoiceCorrectness.d.ts.map +0 -1
- package/dist/delivery/computeDisplayState.d.ts.map +0 -1
- package/dist/delivery/computeLayoutProfile.d.ts.map +0 -1
- package/dist/delivery/computeLayoutStyle.d.ts.map +0 -1
- package/dist/delivery/index.d.ts.map +0 -1
- package/dist/delivery/variant-css-map.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.iife.d.ts.map +0 -1
- package/dist/print/index.d.ts.map +0 -1
- package/dist/shared/layoutLimits.d.ts.map +0 -1
- package/dist/shared/types.d.ts.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["t","e"],"sources":["../../../../../lib-svelte/delivery-events/dist/index2.js","../../../../../lib-svelte/delivery-events/dist/index3.js","../../../src/delivery/computeAudioMode.ts","../../../src/delivery/AudioPlayer.svelte","../../../src/delivery/ClozeMarker.svelte","../../../src/delivery/ChoiceRow.svelte","../../../src/delivery/computeChoiceCorrectness.ts","../../../src/delivery/computeLayoutProfile.ts","../../../src/delivery/computeLayoutStyle.ts","../../../src/delivery/computeDisplayState.ts","../../../src/delivery/variant-css-map.ts","../../../src/delivery/McPopulatedBlank.svelte","../../../src/delivery/index.ts"],"sourcesContent":["//#region ../../shared/player-events/dist/index.js\nvar e = class e extends CustomEvent {\n\tstatic {\n\t\tthis.TYPE = \"model-set\";\n\t}\n\tconstructor(t, n, r) {\n\t\tsuper(e.TYPE, {\n\t\t\tbubbles: !0,\n\t\t\tcomposed: !0,\n\t\t\tdetail: {\n\t\t\t\tcomplete: n,\n\t\t\t\tcomponent: t,\n\t\t\t\thasModel: r\n\t\t\t}\n\t\t}), this.component = t, this.complete = n;\n\t}\n}, t = class e extends CustomEvent {\n\tstatic {\n\t\tthis.TYPE = \"session-changed\";\n\t}\n\tconstructor(t, n) {\n\t\tsuper(e.TYPE, {\n\t\t\tbubbles: !0,\n\t\t\tcomposed: !0,\n\t\t\tdetail: {\n\t\t\t\tcomplete: n,\n\t\t\t\tcomponent: t\n\t\t\t}\n\t\t}), this.component = t, this.complete = n;\n\t}\n};\n//#endregion\nexport { e as ModelSetEvent, t as SessionChangedEvent };\n","import { SessionChangedEvent as e } from \"./index2.js\";\n//#region src/session-bridge.ts\nvar t = (e) => {\n\tlet t = e;\n\treturn t ? typeof t.onSessionChange == \"function\" || typeof t.onAudioStarted == \"function\" || typeof t.onAudioEnded == \"function\" : !1;\n};\nfunction n(e, n = {}) {\n\tlet r = n.hostPredicate ?? t, i = e;\n\tfor (; i;) {\n\t\tif (r(i)) return i;\n\t\ti = i.parentElement;\n\t}\n\tif (typeof document < \"u\" && n.fallbackSelector) {\n\t\tlet e = document.querySelector(n.fallbackSelector);\n\t\tif (r(e)) return e;\n\t}\n\treturn null;\n}\nfunction r({ sourceEl: t, fallbackSelector: r, component: i, complete: a, session: o }) {\n\tlet s = n(t, { fallbackSelector: r });\n\treturn s ? typeof s.onSessionChange == \"function\" ? (s.onSessionChange(o), s) : (s.dispatchEvent(new e(i, a)), s) : null;\n}\n//#endregion\nexport { r as forwardSessionChange, n as resolveDeliveryHost };\n","export type AudioMode = 'feature-button' | 'controls' | 'error' | 'none';\n\nexport function computeAudioMode(params: {\n hasAudio: boolean;\n audioUrl: string | undefined;\n useFeatureButtonAudio: boolean;\n}): AudioMode {\n if (!params.hasAudio) return 'none';\n if (!params.audioUrl) return 'error';\n return params.useFeatureButtonAudio ? 'feature-button' : 'controls';\n}\n","<script lang=\"ts\">\nimport { computeAudioMode } from './computeAudioMode';\n\ninterface AudioButtonSkin {\n silentUrl: string;\n playingUrl: string;\n}\n\ninterface UiText {\n clickToEnableAutoplay: string;\n audioResourceUnavailable: string;\n listenSilentAlt?: string;\n listenPlayingAlt?: string;\n listenSilentAltEs?: string;\n listenPlayingAltEs?: string;\n}\n\nconst AUDIO_PLAYBACK = {\n IDLE: 'idle',\n PLAYING: 'playing',\n BLOCKED: 'blocked',\n PAUSED: 'paused',\n} as const;\ntype AudioPlaybackState = (typeof AUDIO_PLAYBACK)[keyof typeof AUDIO_PLAYBACK];\n\nlet {\n hasAudio = false,\n audioUrl,\n useFeatureButtonAudio = false,\n autoplayEnabled = false,\n featureAudioSkin,\n uiText,\n locale = '',\n onaudiostarted,\n onaudioended,\n}: {\n hasAudio?: boolean;\n audioUrl?: string;\n useFeatureButtonAudio?: boolean;\n autoplayEnabled?: boolean;\n featureAudioSkin: AudioButtonSkin;\n uiText: UiText;\n locale?: string;\n onaudiostarted?: () => void;\n onaudioended?: () => void;\n} = $props();\n\nlet audioEl = $state<HTMLAudioElement | null>(null);\nlet featureAudioButtonEl = $state<HTMLButtonElement | null>(null);\nlet autoplayEnableButtonEl = $state<HTMLButtonElement | null>(null);\nlet audioPlaybackState = $state<AudioPlaybackState>(AUDIO_PLAYBACK.IDLE);\n\nconst audioMode = $derived(computeAudioMode({ hasAudio, audioUrl, useFeatureButtonAudio }));\nconst isMediaPlaying = $derived(audioPlaybackState === AUDIO_PLAYBACK.PLAYING);\nconst autoPlayPromptOpen = $derived(audioPlaybackState === AUDIO_PLAYBACK.BLOCKED);\nconst audioErrorMessage = $derived(audioMode === 'error' ? uiText.audioResourceUnavailable : '');\n\n// Reset playback state when audioUrl changes so autoplay re-fires for a new question.\n$effect(() => {\n audioUrl;\n audioPlaybackState = AUDIO_PLAYBACK.IDLE;\n});\n\nfunction playFeatureAudio() {\n if (audioMode !== 'none' && audioMode !== 'error' && audioEl) {\n audioEl.play().catch(() => {});\n }\n}\n\nfunction handleEnableAutoplayClick() {\n if (audioMode !== 'none' && audioMode !== 'error' && audioEl) {\n audioEl.play().finally(() => {\n if (audioPlaybackState === AUDIO_PLAYBACK.BLOCKED) audioPlaybackState = AUDIO_PLAYBACK.PAUSED;\n });\n }\n}\n\nfunction useListener<K extends keyof HTMLElementEventMap>(\n getEl: () => EventTarget | null | undefined,\n event: K,\n handler: (e: HTMLElementEventMap[K]) => void\n) {\n $effect(() => {\n const el = getEl();\n if (!el) return;\n el.addEventListener(event, handler as EventListener);\n return () => el.removeEventListener(event, handler as EventListener);\n });\n}\n\nuseListener(\n () => audioEl,\n 'playing',\n () => {\n audioPlaybackState = AUDIO_PLAYBACK.PLAYING;\n onaudiostarted?.();\n }\n);\n\nuseListener(\n () => audioEl,\n 'ended',\n () => {\n audioPlaybackState = AUDIO_PLAYBACK.PAUSED;\n onaudioended?.();\n }\n);\n\nuseListener(\n () => featureAudioButtonEl,\n 'click',\n () => playFeatureAudio()\n);\nuseListener(\n () => autoplayEnableButtonEl,\n 'click',\n () => handleEnableAutoplayClick()\n);\n\n$effect(() => {\n if (!autoplayEnabled || audioMode === 'none' || audioMode === 'error') return;\n if (audioPlaybackState !== AUDIO_PLAYBACK.IDLE) return;\n if (audioEl && audioUrl) {\n audioPlaybackState = AUDIO_PLAYBACK.PAUSED;\n audioEl.play().catch(() => {\n audioPlaybackState = AUDIO_PLAYBACK.BLOCKED;\n });\n }\n});\n\nfunction speechButtonLabel(loc = '') {\n return loc.toLowerCase().startsWith('es') ? 'Escuchar' : 'Listen';\n}\n\nfunction silentAlt(loc = '') {\n return loc.toLowerCase().startsWith('es')\n ? (uiText.listenSilentAltEs ?? 'Escuchar. Repetir las instrucciones.')\n : (uiText.listenSilentAlt ?? 'Repeat instructions');\n}\n\nfunction playingAlt(loc = '') {\n return loc.toLowerCase().startsWith('es')\n ? (uiText.listenPlayingAltEs ?? 'Escuchar. Estas son las instrucciones.')\n : (uiText.listenPlayingAlt ?? 'Instructions are playing');\n}\n</script>\n\n{#if audioMode !== 'none'}\n <div class=\"mb-4 audio-container pie-audio-container\">\n {#if audioMode === 'feature-button'}\n <audio\n bind:this={audioEl}\n class=\"sr-only pie-audio-player\"\n preload=\"metadata\"\n src={audioUrl}\n aria-hidden=\"true\"\n tabindex=\"-1\"\n ></audio>\n <button\n bind:this={featureAudioButtonEl}\n class=\"listen-button pie-listen-button rli-feature-audio\"\n type=\"button\"\n aria-label={speechButtonLabel(locale)}\n >\n <img\n class={`listen-feature-icon pie-listen-icon rli-feature-listen ${isMediaPlaying ? '' : 'listen-active'}`}\n src={featureAudioSkin.silentUrl}\n alt={silentAlt(locale)}\n />\n <img\n class={`listen-feature-icon pie-listen-icon rli-feature-listen ${isMediaPlaying ? 'listen-active' : ''}`}\n src={featureAudioSkin.playingUrl}\n alt={playingAlt(locale)}\n />\n </button>\n {:else if audioMode === 'controls'}\n <audio\n bind:this={audioEl}\n controls\n class=\"w-full max-w-md pie-audio-player\"\n preload=\"metadata\"\n src={audioUrl}\n >\n <track kind=\"captions\" />\n </audio>\n {#if autoPlayPromptOpen}\n <button\n bind:this={autoplayEnableButtonEl}\n class=\"mt-2 text-sm underline pie-audio-autoplay-enable\"\n type=\"button\"\n >\n {uiText.clickToEnableAutoplay}\n </button>\n {/if}\n {:else if audioMode === 'error'}\n <p class=\"text-sm text-red-700 pie-audio-error\" role=\"alert\">{audioErrorMessage}</p>\n {/if}\n </div>\n{/if}\n\n<style>\n .listen-button {\n width: var(--mpb-listen-button-size, 128px);\n height: var(--mpb-listen-button-size, 128px);\n border: 0;\n padding: 0;\n background-color: transparent;\n cursor: pointer;\n z-index: 1;\n }\n\n .listen-button:hover {\n background-color: #e2f1fe;\n }\n\n .listen-feature-icon {\n width: var(--mpb-listen-button-size, 128px);\n height: var(--mpb-listen-button-size, 128px);\n object-fit: contain;\n display: none;\n }\n\n .listen-feature-icon.listen-active {\n display: block;\n }\n\n .sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n</style>\n","<script lang=\"ts\">\ninterface DisplayChoice {\n imageUrl?: string;\n imageAlt?: string;\n labelHtml?: string;\n}\n\nlet {\n choiceMode = 'text',\n displayChoice = undefined,\n displayChoiceLabelHtml = '',\n isStandalone = false,\n blankWidth,\n blankBorderWidth,\n ariaLabel,\n}: {\n choiceMode?: 'text' | 'image';\n displayChoice?: DisplayChoice;\n displayChoiceLabelHtml?: string;\n isStandalone?: boolean;\n blankWidth: string;\n blankBorderWidth: string;\n ariaLabel: string;\n} = $props();\n</script>\n\n<span\n class={`inline-flex items-center min-h-[1.5em] px-2 mx-1 border-b-2 border-gray-500 align-baseline cloze-marker pie-blank-slot ${isStandalone ? 'cloze-marker-standalone pie-blank-slot-standalone' : ''}`}\n style={`width:${blankWidth};border-bottom-width:${blankBorderWidth};`}\n role=\"status\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n aria-label={ariaLabel}\n>\n {#if choiceMode === 'image' && displayChoice?.imageUrl}\n <img\n src={displayChoice.imageUrl}\n alt={displayChoice.imageAlt || 'Selected answer image'}\n class=\"w-auto object-contain pie-blank-image\"\n style=\"max-height:var(--mpb-selected-image-max-height, 4rem);\"\n />\n {:else if displayChoiceLabelHtml}\n <span class=\"cloze-marker-value pie-blank-value\">{@html displayChoiceLabelHtml}</span>\n {:else}\n <span class=\"cloze-marker-empty\" aria-hidden=\"true\"> </span>\n {/if}\n</span>\n\n<style>\n .cloze-marker {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n text-align: center;\n vertical-align: baseline;\n }\n\n .cloze-marker:focus-within {\n outline: 2px solid var(--mpb-focus-ring, #1565c0);\n outline-offset: 2px;\n }\n\n .cloze-marker-standalone {\n width: var(--mpb-blank-standalone-width, 7rem);\n }\n\n .cloze-marker-empty {\n display: inline-block;\n min-width: 4ch;\n }\n\n .cloze-marker-value {\n width: 100%;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n text-align: center;\n }\n\n .cloze-marker-value :global(p) {\n margin: 0;\n }\n</style>\n","<script lang=\"ts\">\ninterface Choice {\n id: string;\n labelHtml?: string;\n imageUrl?: string;\n imageAlt?: string;\n}\n\nlet {\n choice,\n choiceMode = 'text',\n isHorizontal = false,\n isSelected = false,\n isDisabled = false,\n correctness = undefined,\n isEvaluateMode = false,\n instanceId,\n radioGroupName,\n}: {\n choice: Choice;\n choiceMode?: 'text' | 'image';\n isHorizontal?: boolean;\n isSelected?: boolean;\n isDisabled?: boolean;\n correctness?: 'correct' | 'incorrect' | undefined;\n isEvaluateMode?: boolean;\n instanceId: string;\n radioGroupName: string;\n} = $props();\n</script>\n\n<div\n class={`flex items-start choice-row pie-choice ${isHorizontal ? 'choice-row-horizontal pie-choice-horizontal' : ''} ${isSelected ? 'is-selected pie-choice-selected' : ''} ${correctness ? `choice-${correctness} pie-choice-${correctness}` : ''}`}\n style=\"gap:var(--mpb-choice-row-gap, 0.5rem);\"\n>\n {#if isHorizontal}\n <label\n for={`${instanceId}-opt-${choice.id}`}\n class=\"cursor-pointer choice-tile text-center pie-choice-tile\"\n >\n <span class=\"choice-tile-content pie-choice-tile-content\">\n {#if choiceMode === 'image' && choice.imageUrl}\n <img\n src={choice.imageUrl}\n alt={choice.imageAlt || `Choice ${choice.id}`}\n class=\"object-contain pie-choice-image\"\n style=\"max-height:var(--mpb-choice-image-max-height, 5rem);\"\n />\n {:else}\n <span class=\"choice-html pie-choice-label\">{@html choice.labelHtml || ''}</span>\n {/if}\n </span>\n <input\n type=\"radio\"\n name={radioGroupName}\n id={`${instanceId}-opt-${choice.id}`}\n value={choice.id}\n checked={isSelected}\n disabled={isDisabled}\n class=\"choice-radio-bottom pie-choice-radio pie-choice-radio-bottom\"\n />\n </label>\n {:else}\n <input\n type=\"radio\"\n name={radioGroupName}\n id={`${instanceId}-opt-${choice.id}`}\n value={choice.id}\n checked={isSelected}\n disabled={isDisabled}\n class=\"choice-radio-inline pie-choice-radio pie-choice-radio-inline\"\n />\n <label for={`${instanceId}-opt-${choice.id}`} class=\"cursor-pointer flex-1 pie-choice-label-wrap\">\n {#if choiceMode === 'image' && choice.imageUrl}\n <img\n src={choice.imageUrl}\n alt={choice.imageAlt || `Choice ${choice.id}`}\n class=\"object-contain pie-choice-image\"\n style=\"max-height:var(--mpb-choice-image-max-height, 5rem);\"\n />\n {:else}\n <span class=\"choice-html pie-choice-label\">{@html choice.labelHtml || ''}</span>\n {/if}\n </label>\n {/if}\n {#if isEvaluateMode && correctness}\n <span\n class={`pie-choice-feedback-badge ${correctness === 'correct' ? 'pie-choice-feedback-correct' : 'pie-choice-feedback-incorrect'}`}\n aria-hidden=\"true\"\n >\n {correctness === 'correct' ? '✓' : '✕'}\n </span>\n {/if}\n</div>\n\n<style>\n .choice-row-horizontal {\n flex-direction: column;\n align-items: center;\n width: min(var(--mpb-choice-width-px, 170px), var(--mpb-choice-width-vw, 30vw));\n min-height: var(--mpb-choice-tile-min-height, 11rem);\n gap: 0;\n }\n\n .choice-tile {\n display: flex;\n flex-direction: column;\n justify-content: space-between;\n align-items: center;\n width: 100%;\n min-height: var(--mpb-choice-tile-min-height, 11rem);\n padding: 0.8rem 0.65rem 0.5rem;\n border-radius: 8px;\n background: transparent;\n transition: background-color 120ms ease-in-out;\n }\n\n .choice-tile-content {\n width: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: var(--mpb-choice-content-min-height, 7.5rem);\n }\n\n .choice-row-horizontal:hover .choice-tile {\n background: var(--mpb-choice-hover-bg, var(--pie-background-dark, #ecedf1));\n }\n\n .pie-choice-horizontal:not(.is-selected):not(:hover) .pie-choice-tile {\n background: transparent;\n }\n\n .choice-row-horizontal.is-selected .choice-tile {\n background: var(--mpb-choice-selected-bg, var(--pie-secondary-background, rgba(241, 241, 241, 1)));\n }\n\n .choice-row-horizontal.is-selected:hover .choice-tile {\n background: var(--mpb-choice-selected-bg, var(--pie-secondary-background, rgba(241, 241, 241, 1)));\n }\n\n .pie-choice:not(.pie-choice-horizontal):hover .pie-choice-label-wrap {\n background: var(--pie-background-dark, #ecedf1);\n }\n\n .pie-choice:not(.pie-choice-horizontal):not(.is-selected):not(:hover) .pie-choice-label-wrap {\n background: transparent;\n }\n\n .pie-choice:not(.pie-choice-horizontal).is-selected .pie-choice-label-wrap {\n background: var(--pie-secondary-background, rgba(241, 241, 241, 1));\n border-radius: 6px;\n }\n\n .pie-choice:not(.pie-choice-horizontal).is-selected:hover .pie-choice-label-wrap {\n background: var(--pie-secondary-background, rgba(241, 241, 241, 1));\n }\n\n .pie-choice.choice-correct {\n border-left: 3px solid var(--pie-correct-tertiary, #0ea449);\n }\n\n .pie-choice.choice-incorrect {\n border-left: 3px solid var(--pie-incorrect-icon, #bf0d00);\n }\n\n .pie-choice-horizontal.choice-correct .choice-tile {\n background: var(--pie-correct-secondary, #e8f5e9);\n }\n\n .pie-choice-horizontal.choice-incorrect .choice-tile {\n background: var(--pie-incorrect-secondary, #ffebee);\n }\n\n .pie-choice-feedback-badge {\n margin-left: auto;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.1rem;\n height: 1.1rem;\n border-radius: 9999px;\n font-size: 0.72rem;\n line-height: 1;\n font-weight: 700;\n color: var(--pie-white, #ffffff);\n }\n\n .pie-choice-feedback-correct {\n background: var(--pie-correct-icon, #087d38);\n }\n\n .pie-choice-feedback-incorrect {\n background: var(--pie-incorrect-icon, #bf0d00);\n }\n\n .choice-row-horizontal :global(p) {\n margin: 0;\n text-align: center;\n }\n\n .choice-html :global(p) {\n margin: 0;\n }\n\n .choice-html {\n width: 100%;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n text-align: center;\n }\n\n .choice-radio-bottom {\n margin-top: var(--mpb-horizontal-choice-radio-top-margin, 0.5rem);\n padding: var(--mpb-choice-radio-padding, 0px);\n }\n\n .choice-radio-inline {\n margin-top: var(--mpb-horizontal-choice-radio-top-margin, 0.5rem);\n }\n</style>\n","export interface ChoiceCorrectnessParams {\n isEvaluateMode: boolean;\n correctChoiceId: string;\n selectedId: string;\n showCorrectAnswer: boolean;\n}\n\n/**\n * Computes which choice ids should display a correctness badge and what kind.\n *\n * Reveal mode (showCorrectAnswer=true) shows only the canonical correct answer —\n * the student's wrong selection is deliberately suppressed so the UI only\n * highlights what to remember, not what to regret.\n *\n * Unanswered-in-evaluate (selectedId='') treats the correct choice as missed\n * (incorrect badge) rather than triggering the two-badge wrong-answer path.\n */\nexport function computeChoiceCorrectness(\n params: ChoiceCorrectnessParams\n): Map<string, 'correct' | 'incorrect'> {\n const map = new Map<string, 'correct' | 'incorrect'>();\n const { isEvaluateMode, correctChoiceId, selectedId, showCorrectAnswer } = params;\n\n if (!isEvaluateMode || !correctChoiceId) {\n return map;\n }\n if (showCorrectAnswer) {\n map.set(correctChoiceId, 'correct');\n return map;\n }\n if (!selectedId) {\n map.set(correctChoiceId, 'incorrect');\n return map;\n }\n if (selectedId === correctChoiceId) {\n map.set(correctChoiceId, 'correct');\n return map;\n }\n map.set(selectedId, 'incorrect');\n map.set(correctChoiceId, 'incorrect');\n return map;\n}\n","const BLANK_TOKEN = '{{blank}}';\n\nexport interface LayoutProfileParams {\n interactionMode?: string;\n template?: string;\n choiceLayout?: string;\n layoutProfile?: string;\n hasAudio?: boolean;\n useFeatureButtonAudio?: boolean | null;\n}\n\nexport interface LayoutProfileResult {\n isAudioOnlyMode: boolean;\n isBlankOnlyTemplate: boolean;\n choiceLayout: 'horizontal' | 'vertical';\n isHorizontalChoices: boolean;\n hasInlineSentenceAudioLayout: boolean;\n useFeatureButtonAudio: boolean;\n}\n\nconst FEATURE_BUTTON_PROFILES = new Set([\n 'audio_blank_only',\n 'stimulus_image_blank',\n 'token_sequence',\n]);\n\nexport function computeLayoutProfile(params: LayoutProfileParams): LayoutProfileResult {\n const {\n interactionMode = '',\n template = '',\n choiceLayout: configuredChoiceLayout,\n layoutProfile = '',\n hasAudio = false,\n useFeatureButtonAudio: configuredFeatureButton,\n } = params;\n\n const isAudioOnlyMode = interactionMode === 'audio_mc_only';\n\n const isBlankOnlyTemplate = (() => {\n if (!template) return false;\n const plain = template\n .replace(/<[^>]+>/g, '')\n .replace(/ /g, ' ')\n .trim();\n return plain === BLANK_TOKEN;\n })();\n\n const choiceLayout: 'horizontal' | 'vertical' =\n configuredChoiceLayout === 'horizontal' || configuredChoiceLayout === 'vertical'\n ? (configuredChoiceLayout as 'horizontal' | 'vertical')\n : isAudioOnlyMode || isBlankOnlyTemplate\n ? 'horizontal'\n : 'vertical';\n\n const isHorizontalChoices = choiceLayout === 'horizontal';\n\n const hasInlineSentenceAudioLayout = layoutProfile === 'inline_sentence' && hasAudio;\n\n const useFeatureButtonAudio =\n typeof configuredFeatureButton === 'boolean'\n ? configuredFeatureButton\n : hasAudio && FEATURE_BUTTON_PROFILES.has(layoutProfile);\n\n return {\n isAudioOnlyMode,\n isBlankOnlyTemplate,\n choiceLayout,\n isHorizontalChoices,\n hasInlineSentenceAudioLayout,\n useFeatureButtonAudio,\n };\n}\n","import { type LayoutLimits, DEFAULT_LAYOUT_LIMITS } from '../shared/layoutLimits';\nexport type { LayoutLimits };\nexport { DEFAULT_LAYOUT_LIMITS };\n\n/**\n * Maps every LayoutLimits key (except legendMaxChars, which is a return value not a CSS var)\n * to its --mpb-* CSS variable name and CSS unit.\n * Add a single entry here when adding a new layout limit.\n */\nexport const CSS_VAR_SPEC: Record<\n Exclude<keyof LayoutLimits, 'legendMaxChars'>,\n { varName: string; unit: string }\n> = {\n blankStandaloneWidthRem: { varName: '--mpb-blank-standalone-width', unit: 'rem' },\n blankWideWidthRem: { varName: '--mpb-blank-wide-width', unit: 'rem' },\n blankUnderlineWidthPx: { varName: '--mpb-blank-underline-width', unit: 'px' },\n blankUnderlineWideWidthPx: { varName: '--mpb-blank-underline-wide-width', unit: 'px' },\n horizontalChoiceWidthPx: { varName: '--mpb-choice-width-px', unit: 'px' },\n horizontalChoiceWidthVw: { varName: '--mpb-choice-width-vw', unit: 'vw' },\n horizontalChoiceTileMinHeightRem: { varName: '--mpb-choice-tile-min-height', unit: 'rem' },\n horizontalChoiceContentMinHeightRem: { varName: '--mpb-choice-content-min-height', unit: 'rem' },\n choiceImageMaxHeightRem: { varName: '--mpb-choice-image-max-height', unit: 'rem' },\n selectedImageMaxHeightRem: { varName: '--mpb-selected-image-max-height', unit: 'rem' },\n choiceGroupGapRem: { varName: '--mpb-choice-group-gap', unit: 'rem' },\n choiceRowGapRem: { varName: '--mpb-choice-row-gap', unit: 'rem' },\n horizontalChoiceRadioTopMarginRem: {\n varName: '--mpb-horizontal-choice-radio-top-margin',\n unit: 'rem',\n },\n narrowHorizontalChoiceMaxWidthPx: { varName: '--mpb-narrow-choice-max-width', unit: 'px' },\n toggleButtonGapRem: { varName: '--mpb-toggle-button-gap', unit: 'rem' },\n listenButtonSizePx: { varName: '--mpb-listen-button-size', unit: 'px' },\n audioBlankTemplateMarginTopRem: { varName: '--mpb-audio-blank-template-margin-top', unit: 'rem' },\n audioBlankTemplateMarginBottomRem: {\n varName: '--mpb-audio-blank-template-margin-bottom',\n unit: 'rem',\n },\n audioInstructionsMaxWidthPx: { varName: '--mpb-audio-instructions-max-width', unit: 'px' },\n stimulusMinColumnPx: { varName: '--mpb-stimulus-min-column', unit: 'px' },\n textMinColumnPx: { varName: '--mpb-text-min-column', unit: 'px' },\n stimulusGridColumnGapRem: { varName: '--mpb-stimulus-grid-column-gap', unit: 'rem' },\n stimulusGridRowGapRem: { varName: '--mpb-stimulus-grid-row-gap', unit: 'rem' },\n stimulusSentenceMarginTopRem: { varName: '--mpb-stimulus-sentence-margin-top', unit: 'rem' },\n stimulusChoicesMarginTopRem: { varName: '--mpb-stimulus-choices-margin-top', unit: 'rem' },\n tokenGridColumnGapRem: { varName: '--mpb-token-grid-column-gap', unit: 'rem' },\n tokenGridRowGapRem: { varName: '--mpb-token-grid-row-gap', unit: 'rem' },\n tokenTemplateMarginTopRem: { varName: '--mpb-token-template-margin-top', unit: 'rem' },\n tokenInlineTokenGapRem: { varName: '--mpb-token-inline-token-gap', unit: 'rem' },\n tokenChoicesMarginTopRem: { varName: '--mpb-token-choices-margin-top', unit: 'rem' },\n inlineGridColumnGapRem: { varName: '--mpb-inline-grid-column-gap', unit: 'rem' },\n inlineGridRowGapRem: { varName: '--mpb-inline-grid-row-gap', unit: 'rem' },\n inlineTemplateMarginTopRem: { varName: '--mpb-inline-template-margin-top', unit: 'rem' },\n inlineChoicesMarginTopRem: { varName: '--mpb-inline-choices-margin-top', unit: 'rem' },\n};\n\nexport const DEFAULT_LAYOUT_PROFILE_PRESETS: Record<string, Partial<LayoutLimits>> = {\n audio_blank_only: {\n blankWideWidthRem: 10,\n blankUnderlineWideWidthPx: 6,\n horizontalChoiceTileMinHeightRem: 11.25,\n horizontalChoiceContentMinHeightRem: 9.375,\n choiceGroupGapRem: 1,\n audioBlankTemplateMarginBottomRem: 1.875,\n },\n stimulus_image_blank: {\n blankWideWidthRem: 10,\n blankUnderlineWideWidthPx: 6,\n },\n token_sequence: {\n blankStandaloneWidthRem: 7,\n blankUnderlineWideWidthPx: 6,\n },\n};\n\nexport interface LayoutStyleResult {\n rootStyle: string;\n blankWidth: string;\n blankBorderWidth: string;\n legendMaxChars: number;\n}\n\nexport function computeLayoutStyle(params: {\n layoutProfile: string;\n isBlankOnlyTemplate: boolean;\n configuredLimits: unknown;\n customProfilePresets: unknown;\n}): LayoutStyleResult {\n const { layoutProfile, isBlankOnlyTemplate } = params;\n\n const configured =\n params.configuredLimits && typeof params.configuredLimits === 'object'\n ? (params.configuredLimits as Partial<LayoutLimits>)\n : {};\n const customPresets =\n params.customProfilePresets && typeof params.customProfilePresets === 'object'\n ? (params.customProfilePresets as Record<string, unknown>)\n : {};\n const customForProfile =\n customPresets[layoutProfile] && typeof customPresets[layoutProfile] === 'object'\n ? (customPresets[layoutProfile] as Partial<LayoutLimits>)\n : {};\n const profilePreset: Partial<LayoutLimits> = {\n ...(DEFAULT_LAYOUT_PROFILE_PRESETS[layoutProfile] ?? {}),\n ...customForProfile,\n };\n const l: LayoutLimits = { ...DEFAULT_LAYOUT_LIMITS, ...configured, ...profilePreset };\n\n const wideBlankProfiles = ['audio_blank_only', 'stimulus_image_blank'];\n const wideUnderlineProfiles = ['audio_blank_only', 'stimulus_image_blank', 'token_sequence'];\n\n const blankWidth = wideBlankProfiles.includes(layoutProfile)\n ? `${l.blankWideWidthRem}rem`\n : isBlankOnlyTemplate\n ? `${l.blankStandaloneWidthRem}rem`\n : 'auto';\n\n const blankBorderWidth = wideUnderlineProfiles.includes(layoutProfile)\n ? `${l.blankUnderlineWideWidthPx}px`\n : `${l.blankUnderlineWidthPx}px`;\n\n const cssVars = (Object.keys(CSS_VAR_SPEC) as (keyof typeof CSS_VAR_SPEC)[]).map(\n (key) => `${CSS_VAR_SPEC[key].varName}:${l[key]}${CSS_VAR_SPEC[key].unit}`\n );\n const rootStyle = cssVars.join(';');\n\n return { rootStyle, blankWidth, blankBorderWidth, legendMaxChars: l.legendMaxChars };\n}\n","export type AudioButtonSkin = { silentUrl: string; playingUrl: string };\n\nexport const DEFAULT_AUDIO_BUTTON_SKINS: Record<string, AudioButtonSkin> = {\n default: {\n silentUrl:\n 'https://assets.learnosity.com/organisations/844/0c9f2aa3-3cd5-4de7-93ef-541c24ca35da.svg',\n playingUrl:\n 'https://assets.learnosity.com/organisations/844/231dfdc2-c113-4be5-91fb-e75a0ca5994b.svg',\n },\n es: {\n silentUrl:\n 'https://assets.learnosity.com/organisations/844/27a9d5b5-d873-4bd5-b9ba-22748782d8ba.svg',\n playingUrl:\n 'https://assets.learnosity.com/organisations/844/120f216d-96b7-4560-94b8-1d90710216b7.svg',\n },\n};\n\n/**\n * Resolves the audio button skin to display.\n * Priority: byLocale[exact] > byLocale[lang] > byLocale.default > customSingle > built-in default\n */\nexport function computeFeatureAudioSkin(params: {\n locale: unknown;\n audioButtonSkin: unknown;\n audioButtonSkinsByLocale: unknown;\n}): AudioButtonSkin {\n const locale = String(params.locale || '').toLowerCase();\n const lang = locale.slice(0, 2);\n const byLocale =\n params.audioButtonSkinsByLocale && typeof params.audioButtonSkinsByLocale === 'object'\n ? (params.audioButtonSkinsByLocale as Record<string, unknown>)\n : {};\n const customSingle =\n params.audioButtonSkin && typeof params.audioButtonSkin === 'object'\n ? (params.audioButtonSkin as AudioButtonSkin)\n : null;\n const defaultSkin = locale.startsWith('es')\n ? DEFAULT_AUDIO_BUTTON_SKINS.es\n : DEFAULT_AUDIO_BUTTON_SKINS.default;\n return (byLocale[locale] ||\n byLocale[lang] ||\n byLocale.default ||\n customSingle ||\n defaultSkin) as AudioButtonSkin;\n}\n\n/**\n * Returns the choice id that the ClozeMarker and selected-state highlight should display.\n * When the correct answer is revealed (alwaysShowCorrect or evaluate+showCorrectAnswer),\n * it shows the correct choice rather than the student's selection.\n */\nexport function computeDisplayChoiceId(params: {\n selectedId: string;\n isEvaluateMode: boolean;\n showCorrectAnswer: boolean;\n alwaysShowCorrect: boolean;\n correctChoiceId: string;\n}): string {\n const { selectedId, isEvaluateMode, showCorrectAnswer, alwaysShowCorrect, correctChoiceId } =\n params;\n if (alwaysShowCorrect && correctChoiceId) return correctChoiceId;\n if (isEvaluateMode && showCorrectAnswer && correctChoiceId) return correctChoiceId;\n return selectedId;\n}\n\n/**\n * Returns the screen-reader-only result announcement text shown after evaluate mode scoring.\n * Empty string means nothing is announced.\n */\nexport function computeResultText(params: {\n isEvaluateMode: boolean;\n showCorrectAnswer: boolean;\n isCorrect: boolean;\n isIncorrect: boolean;\n selectedId: string;\n}): string {\n const { isEvaluateMode, showCorrectAnswer, isCorrect, isIncorrect, selectedId } = params;\n if (!isEvaluateMode || showCorrectAnswer) return '';\n if (isCorrect) return 'Correct answer selected';\n if (isIncorrect && selectedId) return 'Incorrect answer selected';\n return '';\n}\n\n/**\n * Returns the visible legend text for the choices fieldset.\n * Strips HTML, truncates to legendMaxChars with an ellipsis, falls back to answerChoicesLabel.\n */\nexport function computeLegendText(params: {\n prompt: string;\n legendMaxChars: number;\n answerChoicesLabel: string;\n}): string {\n const { prompt, legendMaxChars, answerChoicesLabel } = params;\n const plain = prompt\n .replace(/<[^>]+>/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim();\n const maxChars = Math.max(8, legendMaxChars);\n if (!plain) return answerChoicesLabel;\n return plain.length > maxChars ? `${plain.slice(0, Math.max(1, maxChars - 1))}…` : plain;\n}\n","import selR1BaseCss from './cqt-css/sel-r1-base.css?raw';\nimport selR1PlusgggCss from './cqt-css/sel-r1-plusggg.css?raw';\nimport srVicCss from './cqt-css/sr-vic.css?raw';\nimport selVicCss from './cqt-css/sel-vic.css?raw';\nimport selR1GplusgggCss from './cqt-css/sel-r1-gplusggg.css?raw';\nimport selR1GStemCss from './cqt-css/sel-r1-g-stem.css?raw';\nimport selR1GgPlusCss from './cqt-css/sel-r1-gg-plus.css?raw';\nimport selR1GgplusCss from './cqt-css/sel-r1-ggplus.css?raw';\nimport selR1S3Css from './cqt-css/sel-r1-s3.css?raw';\n\nexport type VariantCssConfig = {\n variantId: string;\n variantClass: string;\n sourceUrl: string;\n cssText: string;\n};\n\nconst VARIANT_BY_CUSTOM_TYPE: Record<string, VariantCssConfig> = {\n 'sel_r1-_plusggg': {\n variantId: 'sel-r1-plusggg',\n variantClass: 'variant-sel-r1-plusggg',\n sourceUrl:\n 'https://global-pr-ibvcustomfiles.renaissance-go.com/learnosity/sel_r1-_plusggg/0.0.1/question.css',\n cssText: selR1PlusgggCss,\n },\n 'sr-vic': {\n variantId: 'sr-vic',\n variantClass: 'variant-sr-vic',\n sourceUrl:\n 'https://global-pr-ibvcustomfiles.renaissance-go.com/learnosity/sr-vic/0.0.1/question.css',\n cssText: srVicCss,\n },\n sel_vic: {\n variantId: 'sel-vic',\n variantClass: 'variant-sel-vic',\n sourceUrl:\n 'https://global-pr-ibvcustomfiles.renaissance-go.com/learnosity/sel_vic/0.0.1/question.css',\n cssText: selVicCss,\n },\n 'sel_r1-_gplusggg': {\n variantId: 'sel-r1-gplusggg',\n variantClass: 'variant-sel-r1-gplusggg',\n sourceUrl:\n 'https://global-pr-ibvcustomfiles.renaissance-go.com/learnosity/sel_r1-_gplusggg/0.0.1/question.css',\n cssText: selR1GplusgggCss,\n },\n 'sel_r1-g_plusggg': {\n variantId: 'sel-r1-g-stem',\n variantClass: 'variant-sel-r1-g-stem',\n sourceUrl:\n 'https://global-pr-ibvcustomfiles.renaissance-go.com/learnosity/sel_r1-g_plusggg/0.0.1/question.css',\n cssText: selR1GStemCss,\n },\n 'sel_r1-gg_plusggg': {\n variantId: 'sel-r1-gg-plus',\n variantClass: 'variant-sel-r1-gg-plus',\n sourceUrl:\n 'https://global-pr-ibvcustomfiles.renaissance-go.com/learnosity/sel_r1-gg_plusggg/0.0.1/question.css',\n cssText: selR1GgPlusCss,\n },\n 'sel_r1-_ggplusggg': {\n variantId: 'sel-r1-ggplus',\n variantClass: 'variant-sel-r1-ggplus',\n sourceUrl:\n 'https://global-pr-ibvcustomfiles.renaissance-go.com/learnosity/sel_r1-_ggplusggg/0.0.1/question.css',\n cssText: selR1GgplusCss,\n },\n 'sel_r1-s3_plusggg': {\n variantId: 'sel-r1-s3',\n variantClass: 'variant-sel-r1-s3',\n sourceUrl:\n 'https://global-pr-ibvcustomfiles.renaissance-go.com/learnosity/sel_r1-s3_plusggg/0.0.1/question.css',\n cssText: selR1S3Css,\n },\n};\n\nconst normalizeCustomType = (value: unknown): string => {\n const normalized = String(value || '')\n .trim()\n .toLowerCase();\n // Accept both base custom types and version-suffixed tags like \"...v0.0.1\".\n return normalized.replace(/v\\d+\\.\\d+\\.\\d+$/i, '');\n};\n\nexport const getVariantCssConfig = (customType: unknown): VariantCssConfig | undefined => {\n const normalized = normalizeCustomType(customType);\n return VARIANT_BY_CUSTOM_TYPE[normalized];\n};\n\nexport const getVariantRootClass = (customType: unknown): string => {\n return getVariantCssConfig(customType)?.variantClass || '';\n};\n\nconst SEL_R1_VARIANT_IDS = new Set([\n 'sel-r1-plusggg',\n 'sel-r1-gplusggg',\n 'sel-r1-g-stem',\n 'sel-r1-gg-plus',\n 'sel-r1-ggplus',\n 'sel-r1-s3',\n]);\n\nconst injectStyleOnce = (id: string, variantName: string, cssText: string): void => {\n const existing = document.getElementById(id) as HTMLStyleElement | null;\n if (existing) {\n if (existing.textContent !== cssText) existing.textContent = cssText;\n return;\n }\n const style = document.createElement('style');\n style.id = id;\n style.setAttribute('data-mpb-variant', variantName);\n style.textContent = cssText;\n document.head.appendChild(style);\n};\n\nexport const ensureVariantCssInjected = (config?: VariantCssConfig): void => {\n if (!config?.cssText || typeof document === 'undefined') {\n return;\n }\n if (SEL_R1_VARIANT_IDS.has(config.variantId)) {\n injectStyleOnce('mc-populated-blank-css-sel-r1-base', 'sel-r1-base', selR1BaseCss);\n }\n injectStyleOnce(`mc-populated-blank-css-${config.variantId}`, config.variantId, config.cssText);\n};\n","<svelte:options\n customElement={{\n shadow: 'none',\n props: {\n model: { type: 'Object' },\n session: { type: 'Object' },\n options: { type: 'Object' },\n },\n }}\n/>\n\n<script lang=\"ts\">\nimport { forwardSessionChange, resolveDeliveryHost } from '@pie-lib/delivery-events-svelte';\nimport AudioPlayer from './AudioPlayer.svelte';\nimport ClozeMarker from './ClozeMarker.svelte';\nimport ChoiceRow from './ChoiceRow.svelte';\nimport { computeChoiceCorrectness } from './computeChoiceCorrectness';\nimport { computeLayoutProfile } from './computeLayoutProfile';\nimport { computeLayoutStyle, DEFAULT_LAYOUT_LIMITS } from './computeLayoutStyle';\nimport {\n computeFeatureAudioSkin,\n computeDisplayChoiceId,\n computeResultText,\n computeLegendText,\n} from './computeDisplayState';\nimport {\n ensureVariantCssInjected,\n getVariantCssConfig,\n getVariantRootClass,\n} from './variant-css-map';\n\nconst BLANK_TOKEN = '{{blank}}';\nconst DEFAULT_UI_TEXT = {\n answerChoices: 'Answer choices',\n selectedAnswerInSentence: 'Selected answer in sentence',\n showCorrectAnswer: 'Show correct answer',\n hideCorrectAnswer: 'Hide correct answer',\n clickToEnableAutoplay: 'Click to enable audio autoplay',\n audioResourceUnavailable: 'Audio is enabled but no playable audio URL is configured.',\n} as const;\n\nlet { model, session } = $props<{ model?: any; session?: any; options?: any }>();\nlet localChoiceId = $state('');\nlet toggleCorrectAnswerButtonEl = $state<HTMLButtonElement | null>(null);\nlet choicesGroupEl = $state<HTMLDivElement | null>(null);\nlet rootEl = $state<HTMLDivElement | null>(null);\nconst instanceId = `mc-populated-blank-${Math.random().toString(36).slice(2, 10)}`;\n\n// ---------------------------------------------------------------------------\n// Cluster: modeFlags — delivery mode, correctness, and answer-reveal state\n// Feeds: shouldShowCorrectAnswerToggle, choiceState, a11y\n// ---------------------------------------------------------------------------\nconst deliveryMode = $derived((model?.mode || model?.env?.mode || '').toString());\nconst isEvaluateMode = $derived(deliveryMode === 'evaluate');\nconst correctness = $derived(model?.correctness);\nconst isResponseCorrect = $derived(\n typeof model?.responseCorrect === 'boolean' ? model.responseCorrect : correctness === 'correct'\n);\nconst isCorrect = $derived(correctness === 'correct');\nconst isIncorrect = $derived(correctness === 'incorrect');\n\nlet showCorrectAnswer = $state(false);\nconst shouldShowCorrectAnswerToggle = $derived(\n isEvaluateMode && !isResponseCorrect && !!model?.correctChoiceId\n);\n\n// ---------------------------------------------------------------------------\n// Cluster: layoutConfig — profile limits, blank sizing, choice layout, audio mode\n// Feeds: layout (rootStyle, blankWidth, blankBorderWidth, legendMaxChars), audioMode, choiceState\n// ---------------------------------------------------------------------------\nconst layoutProfile = $derived(model?.layoutProfile || '');\nconst layoutProfileFlags = $derived(\n computeLayoutProfile({\n interactionMode: model?.interactionMode,\n template: model?.template,\n choiceLayout: model?.choiceLayout,\n layoutProfile,\n hasAudio: model?.hasAudio,\n useFeatureButtonAudio: model?.useFeatureButtonAudio,\n })\n);\nconst isAudioOnlyMode = $derived(layoutProfileFlags.isAudioOnlyMode);\nconst isBlankOnlyTemplate = $derived(layoutProfileFlags.isBlankOnlyTemplate);\nconst isHorizontalChoices = $derived(layoutProfileFlags.isHorizontalChoices);\nconst hasInlineSentenceAudioLayout = $derived(layoutProfileFlags.hasInlineSentenceAudioLayout);\nconst useFeatureButtonAudio = $derived(layoutProfileFlags.useFeatureButtonAudio);\nconst layout = $derived(\n computeLayoutStyle({\n layoutProfile,\n isBlankOnlyTemplate,\n configuredLimits: model?.layoutLimits,\n customProfilePresets: model?.layoutProfilePresets,\n })\n);\n\n// ---------------------------------------------------------------------------\n// Cluster: choiceState — selection, display choice, per-choice correctness, result text\n// Feeds: template blank display, choice rendering, fieldset, result sr-only text\n// ---------------------------------------------------------------------------\nconst choices = $derived(Array.isArray(model?.choices) ? model.choices : []);\nconst choiceMode = $derived(model?.choiceMode || 'text');\nconst selectedId = $derived(session?.choiceId || localChoiceId || '');\nconst radioGroupName = $derived(`${instanceId}-choice-group-${model?.id || '1'}`);\nconst displayChoiceId = $derived(\n computeDisplayChoiceId({\n selectedId,\n isEvaluateMode,\n showCorrectAnswer,\n alwaysShowCorrect: !!model?.alwaysShowCorrect,\n correctChoiceId: String(model?.correctChoiceId || ''),\n })\n);\nconst displayChoice = $derived.by(() => choices.find((c: any) => c.id === displayChoiceId));\nconst displayChoiceLabelHtml = $derived.by(() => String(displayChoice?.labelHtml || ''));\nconst resultText = $derived(\n computeResultText({ isEvaluateMode, showCorrectAnswer, isCorrect, isIncorrect, selectedId })\n);\nconst choiceCorrectnessById = $derived(\n computeChoiceCorrectness({\n isEvaluateMode,\n correctChoiceId: String(model?.correctChoiceId || ''),\n selectedId: String(selectedId || ''),\n showCorrectAnswer,\n })\n);\n\n// ---------------------------------------------------------------------------\n// Cluster: a11y — stable IDs, aria labelling, described-by relationships\n// Feeds: fieldset legend, radiogroup labelling, template described-by\n// ---------------------------------------------------------------------------\nconst uiText = $derived.by(() => ({\n ...DEFAULT_UI_TEXT,\n ...(model?.uiText || {}),\n}));\nconst promptId = $derived(`${instanceId}-prompt`);\nconst legendId = $derived(`${instanceId}-choices-legend`);\nconst resultId = $derived(`${instanceId}-result`);\nconst legendText = $derived(\n computeLegendText({\n prompt: model?.prompt || '',\n legendMaxChars: layout.legendMaxChars,\n answerChoicesLabel: uiText.answerChoices,\n })\n);\nconst choicesGroupLabelledBy = $derived(model?.prompt ? promptId : undefined);\nconst choicesGroupAriaLabel = $derived.by(() => {\n if (model?.prompt) return undefined;\n const explicit = String(model?.choiceGroupLabel || '').trim();\n if (explicit) return explicit;\n return legendText;\n});\n// The transcript is not among these: it is rendered by the player from the item's\n// accessibility catalog (PIE-902), so this element neither owns the node nor has\n// an id to point at. It is placed immediately before this content in reading\n// order instead, as a labelled region.\nconst templateDescribedBy = $derived.by(() => (model?.prompt ? promptId : undefined));\n\n// ---------------------------------------------------------------------------\n// Misc — locale, audio error, template parsing, variant CSS, style strings\n// ---------------------------------------------------------------------------\nconst lang = $derived.by(() => {\n const locale = model?.locale || '';\n return locale ? locale.slice(0, 2) : 'en';\n});\nconst variantCssConfig = $derived(getVariantCssConfig(model?.customType));\nconst variantRootClass = $derived(getVariantRootClass(model?.customType));\nconst templateParts = $derived.by(() => {\n const t = model?.template || '';\n const idx = t.indexOf(BLANK_TOKEN);\n if (idx < 0) return { before: t, after: '' };\n let before = t.slice(0, idx);\n let after = t.slice(idx + BLANK_TOKEN.length);\n // LSY's shared cloze renderer (Renaissance components/src/cloze.js) emits\n // literal ` ` on BOTH sides of the cloze span unconditionally:\n // ` <span ... -cloze-blank></span><span ... -cloze>…</span> `.\n // Mirror that ONLY for inline_sentence layouts (sel-vic, sr-vic, plain\n // sentence). Token-sequence layouts arrange tokens in a grid with explicit\n // sibling-margin spacing, so injecting NBSP throws off those tuned gaps;\n // they don't suffer the wrap-leader symptom either because each token has\n // its own grid placement. This (a) keeps the cloze glued to its neighbors\n // so it doesn't dangle at the start of a wrapped line (CONTOOL-2574), and\n // (b) matches LSY's cloze→adjacent-text gap when the author wrote no\n // whitespace around {{blank}} (CONTOOL-2572: e.g. `…word: {{blank}}.`).\n if (layoutProfile === 'inline_sentence') {\n before = `${before.replace(/\\s+$/, '')} `;\n after = ` ${after.replace(/^\\s+/, '')}`;\n }\n return { before, after };\n});\n\nfunction emitSession(updatedSession: any, sourceEl?: HTMLElement | null) {\n forwardSessionChange({\n sourceEl,\n fallbackSelector: 'mc-populated-blank',\n component: 'mc-populated-blank',\n session: updatedSession,\n complete: !!updatedSession?.choiceId,\n });\n}\n\nfunction onRadioChange(e: Event) {\n const input = e.target as HTMLInputElement;\n if (!input.checked) return;\n const choiceId = input.value;\n localChoiceId = choiceId;\n const updatedSession = {\n ...session,\n id: session?.id || model?.id || '1',\n element: 'mc-populated-blank',\n choiceId,\n };\n emitSession(updatedSession, input);\n}\n\nfunction toggleCorrectAnswer() {\n if (!shouldShowCorrectAnswerToggle) return;\n showCorrectAnswer = !showCorrectAnswer;\n}\n\n$effect(() => {\n if (!isEvaluateMode || isResponseCorrect) {\n showCorrectAnswer = false;\n }\n});\n\nfunction onRadioGroupKeydown(e: KeyboardEvent) {\n if (model?.disabled) return;\n const key = e.key;\n if (!['ArrowDown', 'ArrowRight', 'ArrowUp', 'ArrowLeft'].includes(key)) return;\n e.preventDefault();\n const container = e.currentTarget as HTMLElement;\n const inputs = Array.from(\n container.querySelectorAll('input[type=\"radio\"]:not([disabled])')\n ) as HTMLInputElement[];\n if (inputs.length === 0) return;\n let idx = inputs.findIndex((i) => i.checked);\n if (key === 'ArrowDown' || key === 'ArrowRight') {\n idx = idx < 0 ? 0 : (idx + 1) % inputs.length;\n } else {\n idx = idx < 0 ? inputs.length - 1 : (idx - 1 + inputs.length) % inputs.length;\n }\n const next = inputs[idx];\n next.checked = true;\n next.dispatchEvent(new Event('change', { bubbles: true }));\n next.focus();\n}\n\nconst featureAudioSkin = $derived(\n computeFeatureAudioSkin({\n locale: model?.locale,\n audioButtonSkin: model?.audioButtonSkin,\n audioButtonSkinsByLocale: model?.audioButtonSkinsByLocale,\n })\n);\n\nfunction onAudioStarted() {\n resolveDeliveryHost(rootEl, { fallbackSelector: 'mc-populated-blank' })?.onAudioStarted?.();\n}\n\nfunction onAudioEnded() {\n resolveDeliveryHost(rootEl, { fallbackSelector: 'mc-populated-blank' })?.onAudioEnded?.();\n}\n\n$effect(() => {\n if (session?.choiceId) {\n localChoiceId = session.choiceId;\n }\n});\n\n$effect(() => {\n const btn = toggleCorrectAnswerButtonEl;\n if (!btn) return;\n btn.addEventListener('click', toggleCorrectAnswer);\n return () => btn.removeEventListener('click', toggleCorrectAnswer);\n});\n\n// Delegated listeners on the choices group — two events with a radio-guard on change.\n$effect(() => {\n const group = choicesGroupEl;\n if (!group) return;\n const handleChange = (e: Event) => {\n const target = e.target as HTMLInputElement | null;\n if (target?.type !== 'radio') return;\n onRadioChange(e);\n };\n const handleKeydown = (e: KeyboardEvent) => onRadioGroupKeydown(e);\n group.addEventListener('change', handleChange);\n group.addEventListener('keydown', handleKeydown);\n return () => {\n group.removeEventListener('change', handleChange);\n group.removeEventListener('keydown', handleKeydown);\n };\n});\n\n$effect(() => {\n ensureVariantCssInjected(variantCssConfig);\n});\n</script>\n\n<div\n bind:this={rootEl}\n class={`p-4 mc-populated-blank-root pie-element pie-element-mc-populated-blank pie-delivery-root layout-${layoutProfile} ${variantRootClass} ${hasInlineSentenceAudioLayout ? 'has-inline-audio' : ''}`}\n lang={lang}\n style={layout.rootStyle}\n>\n {#if model?.prompt}\n <div class=\"mb-4 prose pie-prompt\" id={promptId}>{@html model.prompt}</div>\n {/if}\n\n {#if shouldShowCorrectAnswerToggle}\n <div class=\"pie-correct-answer-toggle-row\">\n <button\n bind:this={toggleCorrectAnswerButtonEl}\n type=\"button\"\n class=\"mb-3 pie-toggle-correct-answer\"\n style=\"gap:var(--mpb-toggle-button-gap, 0.5rem);\"\n aria-pressed={showCorrectAnswer}\n data-testid=\"show-correct-answer\"\n >\n <span class=\"pie-correct-answer-toggle-content\">\n <span class=\"pie-correct-answer-toggle-icon-holder\" aria-hidden=\"true\">\n {#if showCorrectAnswer}\n <svg\n class=\"pie-correct-answer-toggle-svg\"\n preserveAspectRatio=\"xMinYMin meet\"\n version=\"1.1\"\n viewBox=\"-283 359 34 35\"\n >\n <circle cx=\"-266\" cy=\"375.9\" r=\"14\" fill=\"var(--pie-tertiary-light, #d0e2f0)\" />\n <path\n d=\"M-280.5,375.9c0-8,6.5-14.5,14.5-14.5s14.5,6.5,14.5,14.5s-6.5,14.5-14.5,14.5S-280.5,383.9-280.5,375.9z M-279.5,375.9c0,7.4,6.1,13.5,13.5,13.5c7.4,0,13.5-6.1,13.5-13.5s-6.1-13.5-13.5-13.5C-273.4,362.4-279.5,368.5-279.5,375.9z\"\n fill=\"var(--pie-tertiary-light, #d0e2f0)\"\n />\n <polygon\n points=\"-265.4,383.1 -258.6,377.2 -261.2,374.2 -264.3,376.9 -268.9,368.7 -272.4,370.6\"\n fill=\"var(--pie-tertiary, #146eb3)\"\n />\n </svg>\n {:else}\n <svg\n class=\"pie-correct-answer-toggle-svg\"\n preserveAspectRatio=\"xMinYMin meet\"\n version=\"1.1\"\n viewBox=\"-129.5 127 34 35\"\n >\n <path\n d=\"M-112.9,160.4c-8.5,0-15.5-6.9-15.5-15.5c0-8.5,6.9-15.5,15.5-15.5s15.5,6.9,15.5,15.5 C-97.4,153.5-104.3,160.4-112.9,160.4z\"\n fill=\"#D0CAC5\"\n stroke=\"#E6E3E0\"\n stroke-width=\"0.75\"\n />\n <path\n d=\"M-113.2,159c-8,0-14.5-6.5-14.5-14.5s6.5-14.5,14.5-14.5s14.5,6.5,14.5,14.5S-105.2,159-113.2,159z\"\n fill=\"#B3ABA4\"\n stroke=\"#CDC7C2\"\n stroke-width=\"0.5\"\n />\n <circle cx=\"-114.2\" cy=\"143.5\" r=\"14\" fill=\"white\" />\n <path\n d=\"M-114.2,158c-8,0-14.5-6.5-14.5-14.5s6.5-14.5,14.5-14.5s14.5,6.5,14.5,14.5S-106.2,158-114.2,158z M-114.2,130c-7.4,0-13.5,6.1-13.5,13.5s6.1,13.5,13.5,13.5s13.5-6.1,13.5-13.5S-106.8,130-114.2,130z\"\n fill=\"var(--pie-background-dark, #ecedf1)\"\n />\n <polygon\n points=\"-114.8,150.7 -121.6,144.8 -119,141.8 -115.9,144.5 -111.3,136.3 -107.8,138.2\"\n fill=\"var(--pie-tertiary, #146eb3)\"\n />\n </svg>\n {/if}\n </span>\n <span class=\"pie-correct-answer-toggle-label\">\n {showCorrectAnswer ? uiText.hideCorrectAnswer : uiText.showCorrectAnswer}\n </span>\n </span>\n </button>\n </div>\n {/if}\n\n <AudioPlayer\n hasAudio={!!model?.hasAudio}\n audioUrl={model?.audioUrl}\n {useFeatureButtonAudio}\n autoplayEnabled={!!model?.autoplayAudioEnabled}\n {featureAudioSkin}\n {uiText}\n locale={model?.locale}\n onaudiostarted={onAudioStarted}\n onaudioended={onAudioEnded}\n />\n\n {#if model?.sentenceHtml}\n <div class=\"mb-3 prose prose-p:my-1 sentence-line pie-sentence-line\" aria-describedby={templateDescribedBy}>\n {@html model.sentenceHtml}\n </div>\n {/if}\n\n {#if !isAudioOnlyMode}\n <div class=\"mb-4 template-line pie-template-line\" aria-describedby={templateDescribedBy}\n >{@html templateParts.before}<ClozeMarker\n {choiceMode}\n displayChoice={displayChoice}\n {displayChoiceLabelHtml}\n isStandalone={isBlankOnlyTemplate}\n blankWidth={layout.blankWidth}\n blankBorderWidth={layout.blankBorderWidth}\n ariaLabel={uiText.selectedAnswerInSentence}\n />{@html templateParts.after}</div>\n {/if}\n\n {#if resultText}\n <p id={resultId} class=\"sr-only pie-result-feedback\" role=\"status\" aria-live=\"polite\">{resultText}</p>\n {/if}\n\n <fieldset class=\"border-0 p-0 m-0 pie-choices-fieldset\" disabled={model?.disabled}>\n <legend class=\"sr-only pie-choices-legend\" id={legendId}>{legendText}</legend>\n <div\n bind:this={choicesGroupEl}\n class={`pie-choices ${isHorizontalChoices ? 'flex flex-row flex-wrap items-start justify-center' : 'flex flex-col'}`}\n style=\"gap:var(--mpb-choice-group-gap, 0.5rem);\"\n role=\"radiogroup\"\n tabindex=\"-1\"\n aria-labelledby={choicesGroupLabelledBy}\n aria-label={choicesGroupAriaLabel}\n aria-describedby={resultText ? resultId : undefined}\n >\n {#each choices as c (c.id)}\n <ChoiceRow\n choice={c}\n {choiceMode}\n isHorizontal={isHorizontalChoices}\n isSelected={displayChoiceId === c.id}\n isDisabled={!!model?.disabled}\n correctness={choiceCorrectnessById.get(c.id)}\n {isEvaluateMode}\n {instanceId}\n {radioGroupName}\n />\n {/each}\n </div>\n </fieldset>\n</div>\n\n<style>\n .sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n\n .mc-populated-blank-root {\n --mpb-focus-ring: var(\n --pie-focus-outline,\n var(--pie-button-focus-outline, var(--pie-focus-checked-border, #1565c0))\n );\n }\n\n .mc-populated-blank-root :global(.prose) {\n max-width: none;\n }\n\n .pie-toggle-correct-answer {\n width: 100%;\n cursor: pointer;\n border: 0;\n background: transparent;\n padding: 0;\n display: flex;\n justify-content: center;\n text-align: center;\n color: var(--pie-text, black);\n }\n\n .pie-correct-answer-toggle-row {\n width: 100%;\n display: flex;\n justify-content: flex-end;\n }\n\n .pie-correct-answer-toggle-content {\n display: flex;\n margin: 0 auto;\n align-items: center;\n }\n\n .pie-correct-answer-toggle-icon-holder {\n width: 25px;\n margin-right: 5px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n }\n\n .pie-correct-answer-toggle-svg {\n width: 25px;\n height: 25px;\n }\n\n .pie-correct-answer-toggle-label {\n width: fit-content;\n min-width: 140px;\n align-self: center;\n vertical-align: middle;\n font-weight: 400;\n user-select: none;\n }\n\n .pie-toggle-correct-answer:hover .pie-correct-answer-toggle-label,\n .pie-toggle-correct-answer:focus-visible .pie-correct-answer-toggle-label {\n text-decoration: underline;\n }\n\n .template-line {\n white-space: pre-wrap;\n }\n\n .template-line :global(p) {\n margin: 0;\n display: inline;\n }\n\n .layout-audio_blank_only :global(.pie-audio-container),\n .layout-stimulus_image_blank :global(.pie-audio-container) {\n display: flex;\n width: min(100%, var(--mpb-audio-instructions-max-width, 875px));\n margin-left: auto;\n margin-right: auto;\n justify-content: flex-end;\n }\n\n .layout-audio_blank_only .template-line,\n .layout-stimulus_image_blank .template-line {\n text-align: center;\n margin: var(--mpb-audio-blank-template-margin-top, 0.8rem) 0\n var(--mpb-audio-blank-template-margin-bottom, 1.8rem);\n }\n\n .layout-audio_blank_only fieldset {\n display: flex;\n justify-content: center;\n }\n\n .layout-audio_blank_only :global(.pie-blank-slot),\n .layout-stimulus_image_blank :global(.pie-blank-slot) {\n width: var(--mpb-blank-wide-width, 10rem);\n border-bottom-width: var(--mpb-blank-underline-wide-width, 6px);\n min-height: 160px;\n padding-bottom: 4px;\n }\n\n .layout-stimulus_image_blank {\n display: grid;\n grid-template-columns: minmax(var(--mpb-stimulus-min-column, 210px), 1fr) auto;\n grid-template-areas:\n 'sentence audio'\n '. template'\n 'choices choices';\n column-gap: var(--mpb-stimulus-grid-column-gap, 2rem);\n row-gap: var(--mpb-stimulus-grid-row-gap, 0.7rem);\n align-items: start;\n }\n\n .layout-stimulus_image_blank :global(.pie-audio-container) {\n grid-area: audio;\n margin: 0;\n }\n\n .layout-stimulus_image_blank .sentence-line {\n grid-area: sentence;\n margin: var(--mpb-stimulus-sentence-margin-top, 0.2rem) 0 0;\n }\n\n .layout-stimulus_image_blank .template-line {\n grid-area: template;\n margin: 0;\n text-align: center;\n justify-self: center;\n }\n\n .layout-stimulus_image_blank fieldset {\n grid-area: choices;\n margin-top: var(--mpb-stimulus-choices-margin-top, 0.9rem);\n }\n\n .layout-token_sequence {\n display: grid;\n grid-template-columns: 1fr auto;\n grid-template-areas:\n 'audio audio'\n 'template template'\n 'choices choices';\n column-gap: var(--mpb-token-grid-column-gap, 1.5rem);\n row-gap: var(--mpb-token-grid-row-gap, 0.8rem);\n align-items: start;\n }\n\n .layout-token_sequence :global(.pie-audio-container) {\n grid-area: audio;\n margin: 0;\n justify-self: end;\n }\n\n .layout-token_sequence .template-line {\n grid-area: template;\n margin: var(--mpb-token-template-margin-top, 0.6rem) 0 0;\n justify-self: center;\n text-align: center;\n }\n\n .layout-token_sequence .template-line :global(span + span) {\n margin-left: var(--mpb-token-inline-token-gap, 0.35rem);\n }\n\n .layout-token_sequence :global(.pie-blank-slot) {\n width: var(--mpb-blank-standalone-width, 7rem);\n border-bottom-width: var(--mpb-blank-underline-wide-width, 4px);\n margin-left: var(--mpb-token-inline-token-gap, 0.35rem);\n }\n\n .layout-token_sequence fieldset {\n grid-area: choices;\n margin-top: var(--mpb-token-choices-margin-top, 0.2rem);\n }\n\n .layout-inline_sentence.has-inline-audio {\n display: grid;\n grid-template-columns: minmax(var(--mpb-text-min-column, 260px), 1fr) auto;\n grid-template-areas:\n 'template audio'\n 'choices choices';\n column-gap: var(--mpb-inline-grid-column-gap, 1.5rem);\n row-gap: var(--mpb-inline-grid-row-gap, 0.65rem);\n align-items: start;\n }\n\n .layout-inline_sentence.has-inline-audio :global(.pie-audio-container) {\n grid-area: audio;\n margin: 0;\n justify-self: end;\n }\n\n .layout-inline_sentence.has-inline-audio .template-line {\n grid-area: template;\n margin: var(--mpb-inline-template-margin-top, 0.45rem) 0 0;\n text-align: center;\n justify-self: center;\n }\n\n .layout-inline_sentence.has-inline-audio fieldset {\n grid-area: choices;\n margin-top: var(--mpb-inline-choices-margin-top, 0.25rem);\n }\n\n /* Match Learnosity responsive behavior for CQT audio-blank layouts:\n at smaller widths, audio control shifts left and answer tiles stack. */\n @media (max-width: 760px) {\n .layout-audio_blank_only :global(.pie-audio-container),\n .layout-stimulus_image_blank :global(.pie-audio-container),\n .layout-token_sequence :global(.pie-audio-container),\n .layout-inline_sentence.has-inline-audio :global(.pie-audio-container) {\n width: 100%;\n margin-left: 0;\n margin-right: 0;\n justify-content: flex-start;\n justify-self: start;\n }\n\n .layout-audio_blank_only .pie-choices,\n .layout-token_sequence .pie-choices,\n .layout-stimulus_image_blank .pie-choices,\n .layout-inline_sentence.has-inline-audio .pie-choices {\n flex-direction: column;\n align-items: flex-start;\n justify-content: flex-start;\n }\n\n .layout-audio_blank_only .choice-row-horizontal,\n .layout-token_sequence .choice-row-horizontal,\n .layout-stimulus_image_blank .choice-row-horizontal,\n .layout-inline_sentence.has-inline-audio .choice-row-horizontal {\n width: min(100%, var(--mpb-narrow-choice-max-width, 230px));\n align-items: flex-start;\n }\n }\n</style>\n","import McPopulatedBlankComponent from './McPopulatedBlank.svelte';\nimport { ModelSetEvent, SessionChangedEvent } from '@pie-lib/delivery-events-svelte';\n\nfunction isComplete(model: any, session: any, audioComplete = false): boolean {\n if (!session?.choiceId) return false;\n const requiresAudioCompletion =\n !!model?.autoplayAudioEnabled && !!model?.completeAudioEnabled && !!model?.hasAudio;\n if (requiresAudioCompletion && !audioComplete) return false;\n return true;\n}\n\nconst SvelteElementClass = (McPopulatedBlankComponent as any).element;\n\nclass McPopulatedBlankElement extends SvelteElementClass {\n _internalSession: any = null;\n _model: any = null;\n _options: any = null;\n audioComplete = false;\n\n _dispatchModelSet = () => {\n this.dispatchEvent(\n new ModelSetEvent(this.tagName.toLowerCase(), this._isComplete(), this._model !== undefined)\n );\n };\n\n _dispatchSessionChanged = () => {\n this.dispatchEvent(new SessionChangedEvent(this.tagName.toLowerCase(), this._isComplete()));\n };\n\n set model(m: any) {\n this._model = m;\n this.audioComplete = false;\n super.model = m;\n this._dispatchModelSet();\n }\n\n get model() {\n return this._model;\n }\n\n set session(s: any) {\n this._internalSession = s;\n super.session = s;\n this._dispatchSessionChanged();\n }\n\n get session() {\n return this._internalSession;\n }\n\n set options(o: any) {\n this._options = o;\n super.options = o;\n }\n\n get options() {\n return this._options;\n }\n\n onSessionChange = (updatedSession: any) => {\n this._internalSession = updatedSession;\n super.session = updatedSession;\n this._dispatchSessionChanged();\n };\n\n onAudioStarted = () => {\n this._internalSession = {\n ...(this._internalSession || {}),\n audioStartTime: Date.now(),\n };\n };\n\n onAudioEnded = () => {\n this.audioComplete = true;\n this._internalSession = {\n ...(this._internalSession || {}),\n audioEndTime: Date.now(),\n };\n this._dispatchSessionChanged();\n };\n\n _isComplete = () => {\n return isComplete(this._model, this._internalSession, this.audioComplete);\n };\n\n connectedCallback() {\n super.connectedCallback();\n (this as any).onSessionChange = this.onSessionChange;\n (this as any).onAudioStarted = this.onAudioStarted;\n (this as any).onAudioEnded = this.onAudioEnded;\n }\n}\n\nexport default McPopulatedBlankElement;\n"],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
//#region src/shared/layoutLimits.ts
|
|
2
|
+
var e = {
|
|
3
|
+
blankStandaloneWidthRem: 7,
|
|
4
|
+
blankWideWidthRem: 10,
|
|
5
|
+
blankUnderlineWidthPx: 2,
|
|
6
|
+
blankUnderlineWideWidthPx: 4,
|
|
7
|
+
horizontalChoiceWidthPx: 170,
|
|
8
|
+
horizontalChoiceWidthVw: 30,
|
|
9
|
+
horizontalChoiceTileMinHeightRem: 11,
|
|
10
|
+
horizontalChoiceContentMinHeightRem: 7.5,
|
|
11
|
+
selectedImageMaxHeightRem: 4,
|
|
12
|
+
choiceImageMaxHeightRem: 5,
|
|
13
|
+
listenButtonSizePx: 128,
|
|
14
|
+
stimulusMinColumnPx: 210,
|
|
15
|
+
textMinColumnPx: 260,
|
|
16
|
+
legendMaxChars: 120,
|
|
17
|
+
choiceGroupGapRem: .5,
|
|
18
|
+
choiceRowGapRem: .5,
|
|
19
|
+
toggleButtonGapRem: .5,
|
|
20
|
+
horizontalChoiceRadioTopMarginRem: .5,
|
|
21
|
+
audioBlankTemplateMarginTopRem: .8,
|
|
22
|
+
audioBlankTemplateMarginBottomRem: 1.8,
|
|
23
|
+
audioInstructionsMaxWidthPx: 875,
|
|
24
|
+
narrowHorizontalChoiceMaxWidthPx: 230,
|
|
25
|
+
stimulusGridColumnGapRem: 2,
|
|
26
|
+
stimulusGridRowGapRem: .7,
|
|
27
|
+
stimulusSentenceMarginTopRem: .2,
|
|
28
|
+
stimulusChoicesMarginTopRem: .9,
|
|
29
|
+
tokenGridColumnGapRem: 1.5,
|
|
30
|
+
tokenGridRowGapRem: .8,
|
|
31
|
+
tokenTemplateMarginTopRem: .6,
|
|
32
|
+
tokenInlineTokenGapRem: .35,
|
|
33
|
+
tokenChoicesMarginTopRem: .2,
|
|
34
|
+
inlineGridColumnGapRem: 1.5,
|
|
35
|
+
inlineGridRowGapRem: .65,
|
|
36
|
+
inlineTemplateMarginTopRem: .45,
|
|
37
|
+
inlineChoicesMarginTopRem: .25
|
|
38
|
+
};
|
|
39
|
+
//#endregion
|
|
40
|
+
export { e as t };
|
|
41
|
+
|
|
42
|
+
//# sourceMappingURL=layoutLimits-ATKOwLHb.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layoutLimits-ATKOwLHb.js","names":[],"sources":["../../src/shared/layoutLimits.ts"],"sourcesContent":["export type LayoutLimits = {\n blankStandaloneWidthRem: number;\n blankWideWidthRem: number;\n blankUnderlineWidthPx: number;\n blankUnderlineWideWidthPx: number;\n horizontalChoiceWidthPx: number;\n horizontalChoiceWidthVw: number;\n horizontalChoiceTileMinHeightRem: number;\n horizontalChoiceContentMinHeightRem: number;\n selectedImageMaxHeightRem: number;\n choiceImageMaxHeightRem: number;\n listenButtonSizePx: number;\n stimulusMinColumnPx: number;\n textMinColumnPx: number;\n legendMaxChars: number;\n choiceGroupGapRem: number;\n choiceRowGapRem: number;\n toggleButtonGapRem: number;\n horizontalChoiceRadioTopMarginRem: number;\n audioBlankTemplateMarginTopRem: number;\n audioBlankTemplateMarginBottomRem: number;\n audioInstructionsMaxWidthPx: number;\n narrowHorizontalChoiceMaxWidthPx: number;\n stimulusGridColumnGapRem: number;\n stimulusGridRowGapRem: number;\n stimulusSentenceMarginTopRem: number;\n stimulusChoicesMarginTopRem: number;\n tokenGridColumnGapRem: number;\n tokenGridRowGapRem: number;\n tokenTemplateMarginTopRem: number;\n tokenInlineTokenGapRem: number;\n tokenChoicesMarginTopRem: number;\n inlineGridColumnGapRem: number;\n inlineGridRowGapRem: number;\n inlineTemplateMarginTopRem: number;\n inlineChoicesMarginTopRem: number;\n};\n\n/** Baseline values tuned to match historical CQT visuals; override via model.layoutLimits. */\nexport const DEFAULT_LAYOUT_LIMITS: LayoutLimits = {\n blankStandaloneWidthRem: 7,\n blankWideWidthRem: 10,\n blankUnderlineWidthPx: 2,\n blankUnderlineWideWidthPx: 4,\n horizontalChoiceWidthPx: 170,\n horizontalChoiceWidthVw: 30,\n horizontalChoiceTileMinHeightRem: 11,\n horizontalChoiceContentMinHeightRem: 7.5,\n selectedImageMaxHeightRem: 4,\n choiceImageMaxHeightRem: 5,\n listenButtonSizePx: 128,\n stimulusMinColumnPx: 210,\n textMinColumnPx: 260,\n legendMaxChars: 120,\n choiceGroupGapRem: 0.5,\n choiceRowGapRem: 0.5,\n toggleButtonGapRem: 0.5,\n horizontalChoiceRadioTopMarginRem: 0.5,\n audioBlankTemplateMarginTopRem: 0.8,\n audioBlankTemplateMarginBottomRem: 1.8,\n audioInstructionsMaxWidthPx: 875,\n narrowHorizontalChoiceMaxWidthPx: 230,\n stimulusGridColumnGapRem: 2,\n stimulusGridRowGapRem: 0.7,\n stimulusSentenceMarginTopRem: 0.2,\n stimulusChoicesMarginTopRem: 0.9,\n tokenGridColumnGapRem: 1.5,\n tokenGridRowGapRem: 0.8,\n tokenTemplateMarginTopRem: 0.6,\n tokenInlineTokenGapRem: 0.35,\n tokenChoicesMarginTopRem: 0.2,\n inlineGridColumnGapRem: 1.5,\n inlineGridRowGapRem: 0.65,\n inlineTemplateMarginTopRem: 0.45,\n inlineChoicesMarginTopRem: 0.25,\n};\n"],"mappings":";AAuCA,IAAa,IAAsC;CACjD,yBAAyB;CACzB,mBAAmB;CACnB,uBAAuB;CACvB,2BAA2B;CAC3B,yBAAyB;CACzB,yBAAyB;CACzB,kCAAkC;CAClC,qCAAqC;CACrC,2BAA2B;CAC3B,yBAAyB;CACzB,oBAAoB;CACpB,qBAAqB;CACrB,iBAAiB;CACjB,gBAAgB;CAChB,mBAAmB;CACnB,iBAAiB;CACjB,oBAAoB;CACpB,mCAAmC;CACnC,gCAAgC;CAChC,mCAAmC;CACnC,6BAA6B;CAC7B,kCAAkC;CAClC,0BAA0B;CAC1B,uBAAuB;CACvB,8BAA8B;CAC9B,6BAA6B;CAC7B,uBAAuB;CACvB,oBAAoB;CACpB,2BAA2B;CAC3B,wBAAwB;CACxB,0BAA0B;CAC1B,wBAAwB;CACxB,qBAAqB;CACrB,4BAA4B;CAC5B,2BAA2B;AAC7B"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { A as e, C as t, E as n, M as r, N as i, O as a, P as o, S as s, T as c, _ as l, a as u, b as d, d as f, f as p, g as m, h, j as g, k as _, m as v, n as y, p as b, t as x, u as ee, v as S, w as C, x as w } from "../client-BAfWqkS6.js";
|
|
2
|
+
//#region src/print/Print.svelte
|
|
3
|
+
var T = S("<div class=\"mb-4 prose prose-sm svelte-1fx5wwa\"></div>"), E = S("<div class=\"mb-2 prose prose-sm svelte-1fx5wwa\"></div>"), D = S("<img class=\"max-h-14 object-contain\"/>"), O = S("<div class=\"mb-4 prose prose-sm svelte-1fx5wwa\"><!> <span class=\"inline-block min-w-[6rem] border-b-2 border-gray-600 print:border-black px-1\"><!></span> <!></div>"), k = S("<div><strong>Audio:</strong> </div>"), A = S("<div><strong>Transcript:</strong> </div>"), j = S("<div class=\"text-sm mb-4\"><!> <!></div>"), M = S("<span class=\"font-medium\"> </span> <!>", 1), N = S("<span class=\"font-medium\">(key)</span>"), P = S("<!> <!>", 1), F = S("<li><!></li>"), I = S("<div class=\"p-4 print:p-0\"><!> <!> <!> <!> <ul class=\"text-sm list-disc pl-5\"></ul></div>"), L = {
|
|
4
|
+
hash: "svelte-1fx5wwa",
|
|
5
|
+
code: ".prose.svelte-1fx5wwa p {margin:0.5em 0;}.prose.svelte-1fx5wwa strong {font-weight:600;}"
|
|
6
|
+
};
|
|
7
|
+
function R(x, S) {
|
|
8
|
+
i(S, !0), ee(x, L);
|
|
9
|
+
let R = y(S, "model", 7, null), z = _(""), B = _("");
|
|
10
|
+
t(() => {
|
|
11
|
+
a(z, R()?.prompt || "", !0), a(B, R()?.template || "", !0);
|
|
12
|
+
});
|
|
13
|
+
let V = g(() => {
|
|
14
|
+
let e = w(B).indexOf("{{blank}}");
|
|
15
|
+
return e < 0 ? {
|
|
16
|
+
before: w(B),
|
|
17
|
+
after: ""
|
|
18
|
+
} : {
|
|
19
|
+
before: w(B).slice(0, e),
|
|
20
|
+
after: w(B).slice(e + 9)
|
|
21
|
+
};
|
|
22
|
+
}), H = g(() => Array.isArray(R()?.choices) ? R().choices : []), U = g(() => R()?.choices?.find((e) => e.id === R()?.correctChoiceId)), W = g(() => R()?.choiceMode || "text"), G = g(() => R()?.interactionMode === "audio_mc_only"), K = g(() => R()?.printAnswerKey !== !1);
|
|
23
|
+
var q = {
|
|
24
|
+
get model() {
|
|
25
|
+
return R();
|
|
26
|
+
},
|
|
27
|
+
set model(t = null) {
|
|
28
|
+
R(t), e();
|
|
29
|
+
}
|
|
30
|
+
}, J = I(), Y = C(J), te = (e) => {
|
|
31
|
+
var t = T();
|
|
32
|
+
f(t, () => w(z), !0), o(t), m(e, t);
|
|
33
|
+
};
|
|
34
|
+
v(Y, (e) => {
|
|
35
|
+
w(z) && R()?.promptEnabled !== !1 && e(te);
|
|
36
|
+
});
|
|
37
|
+
var X = n(Y, 2), ne = (e) => {
|
|
38
|
+
var t = E();
|
|
39
|
+
f(t, () => R().sentenceHtml, !0), o(t), m(e, t);
|
|
40
|
+
};
|
|
41
|
+
v(X, (e) => {
|
|
42
|
+
R()?.sentenceHtml && e(ne);
|
|
43
|
+
});
|
|
44
|
+
var Z = n(X, 2), re = (e) => {
|
|
45
|
+
var t = O(), r = C(t);
|
|
46
|
+
f(r, () => w(V).before);
|
|
47
|
+
var i = n(r, 2), a = C(i), p = (e) => {
|
|
48
|
+
var t = D();
|
|
49
|
+
s(() => {
|
|
50
|
+
u(t, "src", w(U).imageUrl), u(t, "alt", w(U).imageAlt || "");
|
|
51
|
+
}), m(e, t);
|
|
52
|
+
}, h = (e) => {
|
|
53
|
+
var t = l();
|
|
54
|
+
f(c(t), () => w(U).labelHtml), m(e, t);
|
|
55
|
+
}, g = (e) => {
|
|
56
|
+
m(e, d("________"));
|
|
57
|
+
};
|
|
58
|
+
v(a, (e) => {
|
|
59
|
+
w(K) && w(W) === "image" && w(U)?.imageUrl ? e(p) : w(K) && w(U)?.labelHtml ? e(h, 1) : e(g, -1);
|
|
60
|
+
}), o(i), f(n(i, 2), () => w(V).after), o(t), m(e, t);
|
|
61
|
+
};
|
|
62
|
+
v(Z, (e) => {
|
|
63
|
+
w(G) || e(re);
|
|
64
|
+
});
|
|
65
|
+
var Q = n(Z, 2), ie = (e) => {
|
|
66
|
+
var t = j(), r = C(t), i = (e) => {
|
|
67
|
+
var t = k(), r = n(C(t));
|
|
68
|
+
o(t), s(() => h(r, ` ${R().audioUrl ?? ""}`)), m(e, t);
|
|
69
|
+
};
|
|
70
|
+
v(r, (e) => {
|
|
71
|
+
R()?.audioUrl && e(i);
|
|
72
|
+
});
|
|
73
|
+
var a = n(r, 2), c = (e) => {
|
|
74
|
+
var t = A(), r = n(C(t));
|
|
75
|
+
o(t), s(() => h(r, ` ${R().audioTranscript ?? ""}`)), m(e, t);
|
|
76
|
+
};
|
|
77
|
+
v(a, (e) => {
|
|
78
|
+
R()?.audioTranscript && e(c);
|
|
79
|
+
}), o(t), m(e, t);
|
|
80
|
+
};
|
|
81
|
+
v(Q, (e) => {
|
|
82
|
+
R()?.hasAudio && e(ie);
|
|
83
|
+
});
|
|
84
|
+
var $ = n(Q, 2);
|
|
85
|
+
return p($, 21, () => w(H), b, (e, t) => {
|
|
86
|
+
var r = F(), i = C(r), a = (e) => {
|
|
87
|
+
var r = M(), i = c(r), a = C(i, !0);
|
|
88
|
+
o(i);
|
|
89
|
+
var l = n(i, 2), u = (e) => {
|
|
90
|
+
m(e, d("(key)"));
|
|
91
|
+
};
|
|
92
|
+
v(l, (e) => {
|
|
93
|
+
w(K) && w(t).id === R()?.correctChoiceId && e(u);
|
|
94
|
+
}), s(() => h(a, w(t).id)), m(e, r);
|
|
95
|
+
}, l = (e) => {
|
|
96
|
+
var r = P(), i = c(r);
|
|
97
|
+
f(i, () => w(t).labelHtml || "");
|
|
98
|
+
var a = n(i, 2), o = (e) => {
|
|
99
|
+
m(e, N());
|
|
100
|
+
};
|
|
101
|
+
v(a, (e) => {
|
|
102
|
+
w(K) && w(t).id === R()?.correctChoiceId && e(o);
|
|
103
|
+
}), m(e, r);
|
|
104
|
+
};
|
|
105
|
+
v(i, (e) => {
|
|
106
|
+
w(W) === "image" ? e(a) : e(l, -1);
|
|
107
|
+
}), o(r), m(e, r);
|
|
108
|
+
}), o($), o(J), m(x, J), r(q);
|
|
109
|
+
}
|
|
110
|
+
x(R, { model: { type: "Object" } }, [], []);
|
|
111
|
+
//#endregion
|
|
112
|
+
//#region src/print/index.ts
|
|
113
|
+
var z = R.element, B = class extends z {
|
|
114
|
+
_model = null;
|
|
115
|
+
set model(e) {
|
|
116
|
+
this._model = e, super.model = e;
|
|
117
|
+
}
|
|
118
|
+
get model() {
|
|
119
|
+
return this._model;
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
//#endregion
|
|
123
|
+
export { B as default };
|
|
124
|
+
|
|
125
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/print/Print.svelte","../../../src/print/index.ts"],"sourcesContent":["<svelte:options\n customElement={{\n shadow: 'none',\n props: {\n model: { type: 'Object' },\n },\n }}\n/>\n\n<script lang=\"ts\">\nconst BLANK_TOKEN = '{{blank}}';\n\nlet { model = null }: { model?: any } = $props();\n\nlet prompt = $state('');\nlet template = $state('');\n$effect(() => {\n prompt = model?.prompt || '';\n template = model?.template || '';\n});\n\nconst parts = $derived.by(() => {\n const idx = template.indexOf(BLANK_TOKEN);\n if (idx < 0) return { before: template, after: '' };\n return { before: template.slice(0, idx), after: template.slice(idx + BLANK_TOKEN.length) };\n});\n\nconst choices = $derived(Array.isArray(model?.choices) ? model.choices : []);\nconst correct = $derived(model?.choices?.find((c: any) => c.id === model?.correctChoiceId));\nconst mode = $derived(model?.choiceMode || 'text');\nconst isAudioOnlyMode = $derived(model?.interactionMode === 'audio_mc_only');\nconst showAnswerKey = $derived(model?.printAnswerKey !== false);\n</script>\n\n<div class=\"p-4 print:p-0\">\n {#if prompt && model?.promptEnabled !== false}\n <div class=\"mb-4 prose prose-sm\">{@html prompt}</div>\n {/if}\n\n {#if model?.sentenceHtml}\n <div class=\"mb-2 prose prose-sm\">{@html model.sentenceHtml}</div>\n {/if}\n\n {#if !isAudioOnlyMode}\n <div class=\"mb-4 prose prose-sm\">\n {@html parts.before}\n <span class=\"inline-block min-w-[6rem] border-b-2 border-gray-600 print:border-black px-1\">\n {#if showAnswerKey && mode === 'image' && correct?.imageUrl}\n <img src={correct.imageUrl} alt={correct.imageAlt || ''} class=\"max-h-14 object-contain\" />\n {:else if showAnswerKey && correct?.labelHtml}\n {@html correct.labelHtml}\n {:else}\n ________\n {/if}\n </span>\n {@html parts.after}\n </div>\n {/if}\n\n {#if model?.hasAudio}\n <div class=\"text-sm mb-4\">\n {#if model?.audioUrl}\n <div><strong>Audio:</strong> {model.audioUrl}</div>\n {/if}\n {#if model?.audioTranscript}\n <div><strong>Transcript:</strong> {model.audioTranscript}</div>\n {/if}\n </div>\n {/if}\n\n <ul class=\"text-sm list-disc pl-5\">\n {#each choices as c}\n <li>\n {#if mode === 'image'}\n <span class=\"font-medium\">{c.id}</span>\n {#if showAnswerKey && c.id === model?.correctChoiceId}(key){/if}\n {:else}\n {@html c.labelHtml || ''}\n {#if showAnswerKey && c.id === model?.correctChoiceId}\n <span class=\"font-medium\"> (key)</span>\n {/if}\n {/if}\n </li>\n {/each}\n </ul>\n</div>\n\n<style>\n .prose :global(p) {\n margin: 0.5em 0;\n }\n .prose :global(strong) {\n font-weight: 600;\n }\n</style>\n","import PrintComponent from './Print.svelte';\n\nconst SvelteElementClass = (PrintComponent as any).element;\n\nclass McPopulatedBlankPrint extends SvelteElementClass {\n private _model: any = null;\n\n set model(m: any) {\n this._model = m;\n super.model = m;\n }\n\n get model() {\n return this._model;\n }\n}\n\nexport default McPopulatedBlankPrint;\n"],"mappings":"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"}
|
|
@@ -79,7 +79,6 @@ declare const _default: {
|
|
|
79
79
|
completeAudioEnabled: boolean;
|
|
80
80
|
audioUrl: string;
|
|
81
81
|
audioTranscript: string;
|
|
82
|
-
showVisibleTranscript: boolean;
|
|
83
82
|
locale: string;
|
|
84
83
|
teacherInstructions: string;
|
|
85
84
|
teacherInstructionsEnabled: boolean;
|
|
@@ -92,4 +91,3 @@ declare const _default: {
|
|
|
92
91
|
};
|
|
93
92
|
};
|
|
94
93
|
export default _default;
|
|
95
|
-
//# sourceMappingURL=defaults.d.ts.map
|
|
@@ -65,7 +65,6 @@ export declare const createDefaultModel: (model?: McpbQuestion) => {
|
|
|
65
65
|
completeAudioEnabled: boolean;
|
|
66
66
|
audioUrl: string;
|
|
67
67
|
audioTranscript: string;
|
|
68
|
-
showVisibleTranscript: boolean;
|
|
69
68
|
useFeatureButtonAudio?: boolean;
|
|
70
69
|
locale: string;
|
|
71
70
|
shuffle?: boolean;
|
|
@@ -136,7 +135,6 @@ export declare const normalize: (question?: McpbQuestion) => {
|
|
|
136
135
|
completeAudioEnabled: boolean;
|
|
137
136
|
audioUrl: string;
|
|
138
137
|
audioTranscript: string;
|
|
139
|
-
showVisibleTranscript: boolean;
|
|
140
138
|
useFeatureButtonAudio?: boolean;
|
|
141
139
|
locale: string;
|
|
142
140
|
shuffle?: boolean;
|
|
@@ -153,4 +151,3 @@ export declare const model: (question: McpbQuestion, session: McpbSession | null
|
|
|
153
151
|
export declare const createCorrectResponseSession: (question: McpbQuestion, env: McpbEnv) => Promise<unknown>;
|
|
154
152
|
export declare const validate: (question?: McpbQuestion, _config?: Record<string, unknown>) => Record<string, string>;
|
|
155
153
|
export {};
|
|
156
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/controller/index.js
CHANGED
|
@@ -92,7 +92,6 @@ var defaults_default = {
|
|
|
92
92
|
completeAudioEnabled: false,
|
|
93
93
|
audioUrl: "",
|
|
94
94
|
audioTranscript: "",
|
|
95
|
-
showVisibleTranscript: false,
|
|
96
95
|
locale: "",
|
|
97
96
|
teacherInstructions: "",
|
|
98
97
|
teacherInstructionsEnabled: false
|
|
@@ -219,7 +218,6 @@ var model = async (question, session, env, updateSession) => {
|
|
|
219
218
|
completeAudioEnabled: !!normalizedQuestion.completeAudioEnabled,
|
|
220
219
|
audioUrl: normalizedQuestion.hasAudio ? normalizedQuestion.audioUrl : null,
|
|
221
220
|
audioTranscript: normalizedQuestion.hasAudio ? normalizedQuestion.audioTranscript : null,
|
|
222
|
-
showVisibleTranscript: !!normalizedQuestion.showVisibleTranscript,
|
|
223
221
|
customType: normalizedQuestion.customType || "",
|
|
224
222
|
useFeatureButtonAudio: typeof normalizedQuestion.useFeatureButtonAudio === "boolean" ? normalizedQuestion.useFeatureButtonAudio : void 0,
|
|
225
223
|
locale: normalizedQuestion.locale || "",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/shared/layoutLimits.ts","../../src/controller/defaults.ts","../../src/controller/index.ts"],"sourcesContent":["export type LayoutLimits = {\n blankStandaloneWidthRem: number;\n blankWideWidthRem: number;\n blankUnderlineWidthPx: number;\n blankUnderlineWideWidthPx: number;\n horizontalChoiceWidthPx: number;\n horizontalChoiceWidthVw: number;\n horizontalChoiceTileMinHeightRem: number;\n horizontalChoiceContentMinHeightRem: number;\n selectedImageMaxHeightRem: number;\n choiceImageMaxHeightRem: number;\n listenButtonSizePx: number;\n stimulusMinColumnPx: number;\n textMinColumnPx: number;\n legendMaxChars: number;\n choiceGroupGapRem: number;\n choiceRowGapRem: number;\n toggleButtonGapRem: number;\n horizontalChoiceRadioTopMarginRem: number;\n audioBlankTemplateMarginTopRem: number;\n audioBlankTemplateMarginBottomRem: number;\n audioInstructionsMaxWidthPx: number;\n narrowHorizontalChoiceMaxWidthPx: number;\n stimulusGridColumnGapRem: number;\n stimulusGridRowGapRem: number;\n stimulusSentenceMarginTopRem: number;\n stimulusChoicesMarginTopRem: number;\n tokenGridColumnGapRem: number;\n tokenGridRowGapRem: number;\n tokenTemplateMarginTopRem: number;\n tokenInlineTokenGapRem: number;\n tokenChoicesMarginTopRem: number;\n inlineGridColumnGapRem: number;\n inlineGridRowGapRem: number;\n inlineTemplateMarginTopRem: number;\n inlineChoicesMarginTopRem: number;\n};\n\n/** Baseline values tuned to match historical CQT visuals; override via model.layoutLimits. */\nexport const DEFAULT_LAYOUT_LIMITS: LayoutLimits = {\n blankStandaloneWidthRem: 7,\n blankWideWidthRem: 10,\n blankUnderlineWidthPx: 2,\n blankUnderlineWideWidthPx: 4,\n horizontalChoiceWidthPx: 170,\n horizontalChoiceWidthVw: 30,\n horizontalChoiceTileMinHeightRem: 11,\n horizontalChoiceContentMinHeightRem: 7.5,\n selectedImageMaxHeightRem: 4,\n choiceImageMaxHeightRem: 5,\n listenButtonSizePx: 128,\n stimulusMinColumnPx: 210,\n textMinColumnPx: 260,\n legendMaxChars: 120,\n choiceGroupGapRem: 0.5,\n choiceRowGapRem: 0.5,\n toggleButtonGapRem: 0.5,\n horizontalChoiceRadioTopMarginRem: 0.5,\n audioBlankTemplateMarginTopRem: 0.8,\n audioBlankTemplateMarginBottomRem: 1.8,\n audioInstructionsMaxWidthPx: 875,\n narrowHorizontalChoiceMaxWidthPx: 230,\n stimulusGridColumnGapRem: 2,\n stimulusGridRowGapRem: 0.7,\n stimulusSentenceMarginTopRem: 0.2,\n stimulusChoicesMarginTopRem: 0.9,\n tokenGridColumnGapRem: 1.5,\n tokenGridRowGapRem: 0.8,\n tokenTemplateMarginTopRem: 0.6,\n tokenInlineTokenGapRem: 0.35,\n tokenChoicesMarginTopRem: 0.2,\n inlineGridColumnGapRem: 1.5,\n inlineGridRowGapRem: 0.65,\n inlineTemplateMarginTopRem: 0.45,\n inlineChoicesMarginTopRem: 0.25,\n};\n","import { DEFAULT_LAYOUT_LIMITS } from '../shared/layoutLimits';\n\nexport { DEFAULT_LAYOUT_LIMITS };\n\n/** Token authors must include exactly once in `template` (HTML). */\nexport const BLANK_TOKEN = '{{blank}}';\n\nexport default {\n model: {\n id: '1',\n element: 'mc-populated-blank',\n prompt: '<p><strong>Demo prompt</strong></p>',\n promptEnabled: true,\n interactionMode: 'populate_blank' as const,\n layoutProfile: '',\n choiceLayout: '',\n layoutProfilePresets: {},\n layoutLimits: { ...DEFAULT_LAYOUT_LIMITS },\n audioButtonSkin: null,\n audioButtonSkinsByLocale: {},\n uiText: {\n answerChoices: 'Answer choices',\n selectedAnswerInSentence: 'blank',\n showCorrectAnswer: 'Show correct answer',\n hideCorrectAnswer: 'Hide correct answer',\n clickToEnableAutoplay: 'Click to enable audio autoplay',\n audioResourceUnavailable: 'Audio is enabled but no playable audio URL is configured.',\n transcriptLabel: 'Transcript',\n listenLabelEn: 'Listen',\n listenLabelEs: 'Escuchar',\n listenSilentAlt: 'Repeat instructions',\n listenPlayingAlt: 'Instructions are playing',\n listenSilentAltEs: 'Escuchar. Repetir las instrucciones.',\n listenPlayingAltEs: 'Escuchar. Estas son las instrucciones.',\n },\n sentenceHtml: '',\n template: `<p>The answer is ${BLANK_TOKEN}.</p>`,\n choiceMode: 'text' as const,\n choices: [\n { id: 'c1', labelHtml: '<p>Option A</p>' },\n { id: 'c2', labelHtml: '<p>Option B</p>' },\n { id: 'c3', labelHtml: '<p>Option C</p>' },\n ],\n correctChoiceId: 'c2',\n hasAudio: false,\n autoplayAudioEnabled: false,\n completeAudioEnabled: false,\n audioUrl: '',\n audioTranscript: '',\n showVisibleTranscript: false,\n locale: '',\n teacherInstructions: '',\n teacherInstructionsEnabled: false,\n },\n configuration: {\n prompt: {\n label: 'Prompt',\n settings: true,\n },\n },\n};\n","import defaults, { BLANK_TOKEN, DEFAULT_LAYOUT_LIMITS } from './defaults';\nimport type {\n McpbChoice,\n McpbQuestion,\n McpbSession,\n McpbEnv,\n McpbCorrectness,\n} from '../shared/types';\n\nconst isEmptyObject = (value: unknown): boolean =>\n !!value &&\n typeof value === 'object' &&\n !Array.isArray(value) &&\n Object.keys(value as Record<string, unknown>).length === 0;\n\nexport function countBlankTokens(template: string): number {\n if (!template) return 0;\n const re = /\\{\\{blank\\}\\}/g;\n return (template.match(re) || []).length;\n}\n\nexport const getCorrectness = (question: McpbQuestion, session: McpbSession): McpbCorrectness => {\n if (!session?.choiceId) {\n return 'unanswered';\n }\n const correct = question?.correctChoiceId || '';\n if (session.choiceId === correct) {\n return 'correct';\n }\n return 'incorrect';\n};\n\nexport const getPartialScore = (_question: McpbQuestion, session: McpbSession) => {\n if (!session || isEmptyObject(session) || !session.choiceId) {\n return 0;\n }\n return 1;\n};\n\nexport const outcome = (question: McpbQuestion, session: McpbSession, env: McpbEnv) =>\n new Promise((resolve) => {\n if (!session || isEmptyObject(session)) {\n resolve({\n score: 0,\n empty: true,\n traceLog: ['Student did not select any answers. Score is 0.'],\n });\n return;\n }\n\n session = normalizeSession(session);\n const correctness = getCorrectness(question, session);\n\n if (correctness === 'unanswered') {\n resolve({\n score: 0,\n empty: true,\n traceLog: ['Student did not select any answers. Score is 0.'],\n });\n return;\n }\n\n const score = correctness === 'correct' ? 1 : 0;\n const traceLog = [\n `Mode: ${env?.mode || 'unknown'}.`,\n `Student selected choice: ${session.choiceId}.`,\n `Correct choice: ${question?.correctChoiceId || 'none'}.`,\n `Final score: ${score}.`,\n ];\n resolve({ score, empty: false, traceLog });\n });\n\nexport const createDefaultModel = (model: McpbQuestion = {}) => ({\n ...defaults.model,\n ...model,\n layoutLimits: {\n ...DEFAULT_LAYOUT_LIMITS,\n ...(model?.layoutLimits || {}),\n },\n});\n\nexport const normalize = (question: McpbQuestion = {}) => createDefaultModel(question);\n\nexport const normalizeSession = (s: McpbSession): McpbSession => ({ ...s });\n\nconst shouldShuffleChoices = (question: McpbQuestion) => !!question?.shuffle;\n\nconst shouldLockChoices = (question: McpbQuestion, env: McpbEnv) => {\n if (question?.lockChoiceOrder) return true;\n if (env?.['@pie-element']?.lockChoiceOrder) return true;\n return env?.role === 'instructor';\n};\n\nfunction shuffleArray<T>(items: T[]): T[] {\n const out = [...items];\n for (let i = out.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [out[i], out[j]] = [out[j], out[i]];\n }\n return out;\n}\n\nconst getStoredShuffle = (session: McpbSession): string[] =>\n Array.isArray(session?.data?.shuffledValues)\n ? session.data.shuffledValues\n : Array.isArray(session?.shuffledValues)\n ? session.shuffledValues\n : [];\n\nconst applyShuffledValues = (\n choices: McpbChoice[],\n shuffledValues: string[],\n choiceKey: keyof McpbChoice\n) => {\n const orderedChoices = shuffledValues\n .map((value) => choices.find((choice) => choice?.[choiceKey] === value))\n .filter((c): c is McpbChoice => !!c);\n\n if (orderedChoices.length === choices.length) {\n return orderedChoices;\n }\n\n const orderedValues = new Set(orderedChoices.map((choice) => choice[choiceKey]));\n const leftovers = choices.filter((choice) => !orderedValues.has(choice?.[choiceKey]));\n return [...orderedChoices, ...leftovers];\n};\n\ntype UpdateSessionFn = (\n id: string,\n element: string,\n data: { shuffledValues: string[] }\n) => Promise<void>;\n\nconst getOrderedChoices = async (\n question: McpbQuestion,\n session: McpbSession,\n env: McpbEnv,\n updateSession?: UpdateSessionFn\n) => {\n const choices = Array.isArray(question?.choices) ? [...question.choices] : [];\n if (!choices.length || !shouldShuffleChoices(question)) {\n return choices;\n }\n\n if (shouldLockChoices(question, env || {})) {\n return choices;\n }\n\n const shuffledValues = getStoredShuffle(session);\n if (shuffledValues.length) {\n return applyShuffledValues(choices, shuffledValues, 'id');\n }\n\n const shuffledChoices = shuffleArray(choices);\n\n if (updateSession && typeof updateSession === 'function' && session?.id && session?.element) {\n const shuffledIds = shuffledChoices.map((choice) => choice?.id).filter(Boolean);\n if (shuffledIds.length) {\n await updateSession(session.id, session.element, { shuffledValues: shuffledIds });\n }\n }\n\n return shuffledChoices;\n};\n\nexport const model = async (\n question: McpbQuestion,\n session: McpbSession | null,\n env: McpbEnv | null,\n updateSession?: UpdateSessionFn\n) => {\n const safeSession: McpbSession = session || {};\n const safeEnv: McpbEnv = env || {};\n const normalizedQuestion = normalize(question);\n const choices = await getOrderedChoices(normalizedQuestion, safeSession, safeEnv, updateSession);\n\n const out: Record<string, unknown> = {\n prompt: normalizedQuestion.promptEnabled ? normalizedQuestion.prompt : null,\n interactionMode: normalizedQuestion.interactionMode || 'populate_blank',\n layoutProfile: normalizedQuestion.layoutProfile || '',\n choiceLayout: normalizedQuestion.choiceLayout || '',\n layoutProfilePresets:\n normalizedQuestion.layoutProfilePresets &&\n typeof normalizedQuestion.layoutProfilePresets === 'object'\n ? normalizedQuestion.layoutProfilePresets\n : {},\n layoutLimits: normalizedQuestion.layoutLimits || { ...DEFAULT_LAYOUT_LIMITS },\n audioButtonSkin:\n normalizedQuestion.audioButtonSkin && typeof normalizedQuestion.audioButtonSkin === 'object'\n ? normalizedQuestion.audioButtonSkin\n : null,\n audioButtonSkinsByLocale:\n normalizedQuestion.audioButtonSkinsByLocale &&\n typeof normalizedQuestion.audioButtonSkinsByLocale === 'object'\n ? normalizedQuestion.audioButtonSkinsByLocale\n : {},\n uiText:\n normalizedQuestion.uiText && typeof normalizedQuestion.uiText === 'object'\n ? normalizedQuestion.uiText\n : {},\n sentenceHtml: normalizedQuestion.sentenceHtml || null,\n template: normalizedQuestion.template,\n choiceMode: normalizedQuestion.choiceMode,\n choices,\n hasAudio: normalizedQuestion.hasAudio,\n autoplayAudioEnabled: !!normalizedQuestion.autoplayAudioEnabled,\n completeAudioEnabled: !!normalizedQuestion.completeAudioEnabled,\n audioUrl: normalizedQuestion.hasAudio ? normalizedQuestion.audioUrl : null,\n audioTranscript: normalizedQuestion.hasAudio ? normalizedQuestion.audioTranscript : null,\n showVisibleTranscript: !!normalizedQuestion.showVisibleTranscript,\n customType: normalizedQuestion.customType || '',\n useFeatureButtonAudio:\n typeof normalizedQuestion.useFeatureButtonAudio === 'boolean'\n ? normalizedQuestion.useFeatureButtonAudio\n : undefined,\n locale: normalizedQuestion.locale || '',\n disabled: safeEnv.mode !== 'gather',\n mode: safeEnv.mode,\n };\n\n if (safeEnv.mode === 'evaluate') {\n const correctness = getCorrectness(normalizedQuestion, safeSession);\n out.correctness = correctness;\n out.responseCorrect = correctness === 'correct';\n out.correctChoiceId = normalizedQuestion.correctChoiceId;\n }\n\n if (safeEnv.role === 'instructor' && (safeEnv.mode === 'view' || safeEnv.mode === 'evaluate')) {\n out.teacherInstructions = normalizedQuestion.teacherInstructionsEnabled\n ? normalizedQuestion.teacherInstructions\n : null;\n } else {\n out.teacherInstructions = null;\n }\n\n return out;\n};\n\nexport const createCorrectResponseSession = (question: McpbQuestion, env: McpbEnv) => {\n return new Promise((resolve) => {\n if (env.mode !== 'evaluate' && env.role === 'instructor') {\n resolve({\n id: '1',\n element: 'mc-populated-blank',\n choiceId: question?.correctChoiceId || '',\n });\n } else {\n resolve(null);\n }\n });\n};\n\nexport const validate = (question: McpbQuestion = {}, _config: Record<string, unknown> = {}) => {\n const errors: Record<string, string> = {};\n\n if (question.promptEnabled) {\n const p = question.prompt?.trim() || '';\n if (!p || p === '<p></p>') {\n errors.prompt = 'Prompt is required when prompt is enabled';\n }\n }\n\n const interactionMode = question.interactionMode || 'populate_blank';\n const template = question.template || '';\n const n = countBlankTokens(template);\n if (interactionMode === 'audio_mc_only') {\n if (n > 0) {\n errors.template = `Template cannot contain ${BLANK_TOKEN} in audio-only mode`;\n }\n } else if (interactionMode === 'populate_blank') {\n if (n === 0) {\n errors.template = `Template must contain exactly one ${BLANK_TOKEN} placeholder`;\n } else if (n > 1) {\n errors.template = `Template must contain only one ${BLANK_TOKEN} placeholder`;\n }\n } else {\n errors.interactionMode = 'Unknown interaction mode';\n }\n\n const choices = Array.isArray(question.choices) ? question.choices : [];\n if (choices.length < 2) {\n errors.choices = 'At least two choices are required';\n }\n\n const mode = question.choiceMode || 'text';\n for (let i = 0; i < choices.length; i++) {\n const c = choices[i];\n if (!c?.id) {\n errors.choices = `Choice ${i + 1} is missing an id`;\n break;\n }\n if (mode === 'text') {\n const lbl = (c.labelHtml || '').trim();\n if (!lbl || lbl === '<p></p>') {\n errors.choices = `Choice ${i + 1} needs label text`;\n break;\n }\n } else {\n if (!c.imageUrl?.trim()) {\n errors.choices = `Choice ${i + 1} needs an image URL`;\n break;\n }\n if (!c.imageAlt?.trim()) {\n errors.choices = `Choice ${i + 1} needs image alt text`;\n break;\n }\n }\n }\n\n const correct = question.correctChoiceId;\n if (!correct || !choices.some((c) => c.id === correct)) {\n errors.correctChoiceId = 'Correct choice must match one of the choice ids';\n }\n\n if (question.hasAudio) {\n const hasAudioUrl = !!question.audioUrl?.trim();\n if (!hasAudioUrl) {\n errors.audioUrl = 'A playable audio URL is required when audio is enabled';\n }\n }\n\n const limits = question?.layoutLimits;\n if (limits && typeof limits === 'object') {\n const numericLimitKeys = [\n 'blankStandaloneWidthRem',\n 'blankWideWidthRem',\n 'blankUnderlineWidthPx',\n 'blankUnderlineWideWidthPx',\n 'horizontalChoiceWidthPx',\n 'horizontalChoiceWidthVw',\n 'horizontalChoiceTileMinHeightRem',\n 'horizontalChoiceContentMinHeightRem',\n 'selectedImageMaxHeightRem',\n 'choiceImageMaxHeightRem',\n 'listenButtonSizePx',\n 'stimulusMinColumnPx',\n 'textMinColumnPx',\n 'legendMaxChars',\n 'choiceGroupGapRem',\n 'choiceRowGapRem',\n 'toggleButtonGapRem',\n 'horizontalChoiceRadioTopMarginRem',\n 'audioBlankTemplateMarginTopRem',\n 'audioBlankTemplateMarginBottomRem',\n 'audioInstructionsMaxWidthPx',\n 'narrowHorizontalChoiceMaxWidthPx',\n 'stimulusGridColumnGapRem',\n 'stimulusGridRowGapRem',\n 'stimulusSentenceMarginTopRem',\n 'stimulusChoicesMarginTopRem',\n 'tokenGridColumnGapRem',\n 'tokenGridRowGapRem',\n 'tokenTemplateMarginTopRem',\n 'tokenInlineTokenGapRem',\n 'tokenChoicesMarginTopRem',\n 'inlineGridColumnGapRem',\n 'inlineGridRowGapRem',\n 'inlineTemplateMarginTopRem',\n 'inlineChoicesMarginTopRem',\n ] as const;\n for (const key of numericLimitKeys) {\n if (limits[key] === undefined || limits[key] === null) continue;\n const value = Number(limits[key]);\n if (!Number.isFinite(value) || value <= 0) {\n errors.layoutLimits = `${key} must be a positive number when provided`;\n break;\n }\n }\n }\n\n return errors;\n};\n"],"mappings":";;AAuCA,IAAa,wBAAsC;CACjD,yBAAyB;CACzB,mBAAmB;CACnB,uBAAuB;CACvB,2BAA2B;CAC3B,yBAAyB;CACzB,yBAAyB;CACzB,kCAAkC;CAClC,qCAAqC;CACrC,2BAA2B;CAC3B,yBAAyB;CACzB,oBAAoB;CACpB,qBAAqB;CACrB,iBAAiB;CACjB,gBAAgB;CAChB,mBAAmB;CACnB,iBAAiB;CACjB,oBAAoB;CACpB,mCAAmC;CACnC,gCAAgC;CAChC,mCAAmC;CACnC,6BAA6B;CAC7B,kCAAkC;CAClC,0BAA0B;CAC1B,uBAAuB;CACvB,8BAA8B;CAC9B,6BAA6B;CAC7B,uBAAuB;CACvB,oBAAoB;CACpB,2BAA2B;CAC3B,wBAAwB;CACxB,0BAA0B;CAC1B,wBAAwB;CACxB,qBAAqB;CACrB,4BAA4B;CAC5B,2BAA2B;CAC5B;;;;ACtED,IAAa,cAAc;AAE3B,IAAA,mBAAe;CACb,OAAO;EACL,IAAI;EACJ,SAAS;EACT,QAAQ;EACR,eAAe;EACf,iBAAiB;EACjB,eAAe;EACf,cAAc;EACd,sBAAsB,EAAE;EACxB,cAAc,EAAE,GAAG,uBAAuB;EAC1C,iBAAiB;EACjB,0BAA0B,EAAE;EAC5B,QAAQ;GACN,eAAe;GACf,0BAA0B;GAC1B,mBAAmB;GACnB,mBAAmB;GACnB,uBAAuB;GACvB,0BAA0B;GAC1B,iBAAiB;GACjB,eAAe;GACf,eAAe;GACf,iBAAiB;GACjB,kBAAkB;GAClB,mBAAmB;GACnB,oBAAoB;GACrB;EACD,cAAc;EACd,UAAU,oBAAoB,YAAY;EAC1C,YAAY;EACZ,SAAS;GACP;IAAE,IAAI;IAAM,WAAW;IAAmB;GAC1C;IAAE,IAAI;IAAM,WAAW;IAAmB;GAC1C;IAAE,IAAI;IAAM,WAAW;IAAmB;GAC3C;EACD,iBAAiB;EACjB,UAAU;EACV,sBAAsB;EACtB,sBAAsB;EACtB,UAAU;EACV,iBAAiB;EACjB,uBAAuB;EACvB,QAAQ;EACR,qBAAqB;EACrB,4BAA4B;EAC7B;CACD,eAAe,EACb,QAAQ;EACN,OAAO;EACP,UAAU;EACX,EACF;CACF;;;ACnDD,IAAM,iBAAiB,UACrB,CAAC,CAAC,SACF,OAAO,UAAU,YACjB,CAAC,MAAM,QAAQ,MAAM,IACrB,OAAO,KAAK,MAAiC,CAAC,WAAW;AAE3D,SAAgB,iBAAiB,UAA0B;CACzD,IAAI,CAAC,UAAU,OAAO;CAEtB,QAAQ,SAAS,MAAM,iBAAG,IAAI,EAAE,EAAE;;AAGpC,IAAa,kBAAkB,UAAwB,YAA0C;CAC/F,IAAI,CAAC,SAAS,UACZ,OAAO;CAET,MAAM,UAAU,UAAU,mBAAmB;CAC7C,IAAI,QAAQ,aAAa,SACvB,OAAO;CAET,OAAO;;AAGT,IAAa,mBAAmB,WAAyB,YAAyB;CAChF,IAAI,CAAC,WAAW,cAAc,QAAQ,IAAI,CAAC,QAAQ,UACjD,OAAO;CAET,OAAO;;AAGT,IAAa,WAAW,UAAwB,SAAsB,QACpE,IAAI,SAAS,YAAY;CACvB,IAAI,CAAC,WAAW,cAAc,QAAQ,EAAE;EACtC,QAAQ;GACN,OAAO;GACP,OAAO;GACP,UAAU,CAAC,kDAAkD;GAC9D,CAAC;EACF;;CAGF,UAAU,iBAAiB,QAAQ;CACnC,MAAM,cAAc,eAAe,UAAU,QAAQ;CAErD,IAAI,gBAAgB,cAAc;EAChC,QAAQ;GACN,OAAO;GACP,OAAO;GACP,UAAU,CAAC,kDAAkD;GAC9D,CAAC;EACF;;CAGF,MAAM,QAAQ,gBAAgB,YAAY,IAAI;CAO9C,QAAQ;EAAE;EAAO,OAAO;EAAO,UAAA;GAL7B,SAAS,KAAK,QAAQ,UAAU;GAChC,4BAA4B,QAAQ,SAAS;GAC7C,mBAAmB,UAAU,mBAAmB,OAAO;GACvD,gBAAgB,MAAM;GAEO;EAAU,CAAC;EAC1C;AAEJ,IAAa,sBAAsB,QAAsB,EAAE,MAAM;CAC/D,GAAG,iBAAS;CACZ,GAAG;CACH,cAAc;EACZ,GAAG;EACH,GAAI,OAAO,gBAAgB,EAAE;EAC9B;CACF;AAED,IAAa,aAAa,WAAyB,EAAE,KAAK,mBAAmB,SAAS;AAEtF,IAAa,oBAAoB,OAAiC,EAAE,GAAG,GAAG;AAE1E,IAAM,wBAAwB,aAA2B,CAAC,CAAC,UAAU;AAErE,IAAM,qBAAqB,UAAwB,QAAiB;CAClE,IAAI,UAAU,iBAAiB,OAAO;CACtC,IAAI,MAAM,iBAAiB,iBAAiB,OAAO;CACnD,OAAO,KAAK,SAAS;;AAGvB,SAAS,aAAgB,OAAiB;CACxC,MAAM,MAAM,CAAC,GAAG,MAAM;CACtB,KAAK,IAAI,IAAI,IAAI,SAAS,GAAG,IAAI,GAAG,KAAK;EACvC,MAAM,IAAI,KAAK,MAAM,KAAK,QAAQ,IAAI,IAAI,GAAG;EAC7C,CAAC,IAAI,IAAI,IAAI,MAAM,CAAC,IAAI,IAAI,IAAI,GAAG;;CAErC,OAAO;;AAGT,IAAM,oBAAoB,YACxB,MAAM,QAAQ,SAAS,MAAM,eAAe,GACxC,QAAQ,KAAK,iBACb,MAAM,QAAQ,SAAS,eAAe,GACpC,QAAQ,iBACR,EAAE;AAEV,IAAM,uBACJ,SACA,gBACA,cACG;CACH,MAAM,iBAAiB,eACpB,KAAK,UAAU,QAAQ,MAAM,WAAW,SAAS,eAAe,MAAM,CAAC,CACvE,QAAQ,MAAuB,CAAC,CAAC,EAAE;CAEtC,IAAI,eAAe,WAAW,QAAQ,QACpC,OAAO;CAGT,MAAM,gBAAgB,IAAI,IAAI,eAAe,KAAK,WAAW,OAAO,WAAW,CAAC;CAChF,MAAM,YAAY,QAAQ,QAAQ,WAAW,CAAC,cAAc,IAAI,SAAS,WAAW,CAAC;CACrF,OAAO,CAAC,GAAG,gBAAgB,GAAG,UAAU;;AAS1C,IAAM,oBAAoB,OACxB,UACA,SACA,KACA,kBACG;CACH,MAAM,UAAU,MAAM,QAAQ,UAAU,QAAQ,GAAG,CAAC,GAAG,SAAS,QAAQ,GAAG,EAAE;CAC7E,IAAI,CAAC,QAAQ,UAAU,CAAC,qBAAqB,SAAS,EACpD,OAAO;CAGT,IAAI,kBAAkB,UAAU,OAAO,EAAE,CAAC,EACxC,OAAO;CAGT,MAAM,iBAAiB,iBAAiB,QAAQ;CAChD,IAAI,eAAe,QACjB,OAAO,oBAAoB,SAAS,gBAAgB,KAAK;CAG3D,MAAM,kBAAkB,aAAa,QAAQ;CAE7C,IAAI,iBAAiB,OAAO,kBAAkB,cAAc,SAAS,MAAM,SAAS,SAAS;EAC3F,MAAM,cAAc,gBAAgB,KAAK,WAAW,QAAQ,GAAG,CAAC,OAAO,QAAQ;EAC/E,IAAI,YAAY,QACd,MAAM,cAAc,QAAQ,IAAI,QAAQ,SAAS,EAAE,gBAAgB,aAAa,CAAC;;CAIrF,OAAO;;AAGT,IAAa,QAAQ,OACnB,UACA,SACA,KACA,kBACG;CACH,MAAM,cAA2B,WAAW,EAAE;CAC9C,MAAM,UAAmB,OAAO,EAAE;CAClC,MAAM,qBAAqB,UAAU,SAAS;CAC9C,MAAM,UAAU,MAAM,kBAAkB,oBAAoB,aAAa,SAAS,cAAc;CAEhG,MAAM,MAA+B;EACnC,QAAQ,mBAAmB,gBAAgB,mBAAmB,SAAS;EACvE,iBAAiB,mBAAmB,mBAAmB;EACvD,eAAe,mBAAmB,iBAAiB;EACnD,cAAc,mBAAmB,gBAAgB;EACjD,sBACE,mBAAmB,wBACnB,OAAO,mBAAmB,yBAAyB,WAC/C,mBAAmB,uBACnB,EAAE;EACR,cAAc,mBAAmB,gBAAgB,EAAE,GAAG,uBAAuB;EAC7E,iBACE,mBAAmB,mBAAmB,OAAO,mBAAmB,oBAAoB,WAChF,mBAAmB,kBACnB;EACN,0BACE,mBAAmB,4BACnB,OAAO,mBAAmB,6BAA6B,WACnD,mBAAmB,2BACnB,EAAE;EACR,QACE,mBAAmB,UAAU,OAAO,mBAAmB,WAAW,WAC9D,mBAAmB,SACnB,EAAE;EACR,cAAc,mBAAmB,gBAAgB;EACjD,UAAU,mBAAmB;EAC7B,YAAY,mBAAmB;EAC/B;EACA,UAAU,mBAAmB;EAC7B,sBAAsB,CAAC,CAAC,mBAAmB;EAC3C,sBAAsB,CAAC,CAAC,mBAAmB;EAC3C,UAAU,mBAAmB,WAAW,mBAAmB,WAAW;EACtE,iBAAiB,mBAAmB,WAAW,mBAAmB,kBAAkB;EACpF,uBAAuB,CAAC,CAAC,mBAAmB;EAC5C,YAAY,mBAAmB,cAAc;EAC7C,uBACE,OAAO,mBAAmB,0BAA0B,YAChD,mBAAmB,wBACnB,KAAA;EACN,QAAQ,mBAAmB,UAAU;EACrC,UAAU,QAAQ,SAAS;EAC3B,MAAM,QAAQ;EACf;CAED,IAAI,QAAQ,SAAS,YAAY;EAC/B,MAAM,cAAc,eAAe,oBAAoB,YAAY;EACnE,IAAI,cAAc;EAClB,IAAI,kBAAkB,gBAAgB;EACtC,IAAI,kBAAkB,mBAAmB;;CAG3C,IAAI,QAAQ,SAAS,iBAAiB,QAAQ,SAAS,UAAU,QAAQ,SAAS,aAChF,IAAI,sBAAsB,mBAAmB,6BACzC,mBAAmB,sBACnB;MAEJ,IAAI,sBAAsB;CAG5B,OAAO;;AAGT,IAAa,gCAAgC,UAAwB,QAAiB;CACpF,OAAO,IAAI,SAAS,YAAY;EAC9B,IAAI,IAAI,SAAS,cAAc,IAAI,SAAS,cAC1C,QAAQ;GACN,IAAI;GACJ,SAAS;GACT,UAAU,UAAU,mBAAmB;GACxC,CAAC;OAEF,QAAQ,KAAK;GAEf;;AAGJ,IAAa,YAAY,WAAyB,EAAE,EAAE,UAAmC,EAAE,KAAK;CAC9F,MAAM,SAAiC,EAAE;CAEzC,IAAI,SAAS,eAAe;EAC1B,MAAM,IAAI,SAAS,QAAQ,MAAM,IAAI;EACrC,IAAI,CAAC,KAAK,MAAM,WACd,OAAO,SAAS;;CAIpB,MAAM,kBAAkB,SAAS,mBAAmB;CAEpD,MAAM,IAAI,iBADO,SAAS,YAAY,GACF;CACpC,IAAI,oBAAoB;MAClB,IAAI,GACN,OAAO,WAAW,2BAA2B,YAAY;QAEtD,IAAI,oBAAoB;MACzB,MAAM,GACR,OAAO,WAAW,qCAAqC,YAAY;OAC9D,IAAI,IAAI,GACb,OAAO,WAAW,kCAAkC,YAAY;QAGlE,OAAO,kBAAkB;CAG3B,MAAM,UAAU,MAAM,QAAQ,SAAS,QAAQ,GAAG,SAAS,UAAU,EAAE;CACvE,IAAI,QAAQ,SAAS,GACnB,OAAO,UAAU;CAGnB,MAAM,OAAO,SAAS,cAAc;CACpC,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;EACvC,MAAM,IAAI,QAAQ;EAClB,IAAI,CAAC,GAAG,IAAI;GACV,OAAO,UAAU,UAAU,IAAI,EAAE;GACjC;;EAEF,IAAI,SAAS,QAAQ;GACnB,MAAM,OAAO,EAAE,aAAa,IAAI,MAAM;GACtC,IAAI,CAAC,OAAO,QAAQ,WAAW;IAC7B,OAAO,UAAU,UAAU,IAAI,EAAE;IACjC;;SAEG;GACL,IAAI,CAAC,EAAE,UAAU,MAAM,EAAE;IACvB,OAAO,UAAU,UAAU,IAAI,EAAE;IACjC;;GAEF,IAAI,CAAC,EAAE,UAAU,MAAM,EAAE;IACvB,OAAO,UAAU,UAAU,IAAI,EAAE;IACjC;;;;CAKN,MAAM,UAAU,SAAS;CACzB,IAAI,CAAC,WAAW,CAAC,QAAQ,MAAM,MAAM,EAAE,OAAO,QAAQ,EACpD,OAAO,kBAAkB;CAG3B,IAAI,SAAS;MAEP,CAAC,CADgB,CAAC,SAAS,UAAU,MAAM,EAE7C,OAAO,WAAW;;CAItB,MAAM,SAAS,UAAU;CACzB,IAAI,UAAU,OAAO,WAAW,UAsC9B,KAAK,MAAM,OAAO;EApChB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEgB,EAAkB;EAClC,IAAI,OAAO,SAAS,KAAA,KAAa,OAAO,SAAS,MAAM;EACvD,MAAM,QAAQ,OAAO,OAAO,KAAK;EACjC,IAAI,CAAC,OAAO,SAAS,MAAM,IAAI,SAAS,GAAG;GACzC,OAAO,eAAe,GAAG,IAAI;GAC7B;;;CAKN,OAAO"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/shared/layoutLimits.ts","../../src/controller/defaults.ts","../../src/controller/index.ts"],"sourcesContent":["export type LayoutLimits = {\n blankStandaloneWidthRem: number;\n blankWideWidthRem: number;\n blankUnderlineWidthPx: number;\n blankUnderlineWideWidthPx: number;\n horizontalChoiceWidthPx: number;\n horizontalChoiceWidthVw: number;\n horizontalChoiceTileMinHeightRem: number;\n horizontalChoiceContentMinHeightRem: number;\n selectedImageMaxHeightRem: number;\n choiceImageMaxHeightRem: number;\n listenButtonSizePx: number;\n stimulusMinColumnPx: number;\n textMinColumnPx: number;\n legendMaxChars: number;\n choiceGroupGapRem: number;\n choiceRowGapRem: number;\n toggleButtonGapRem: number;\n horizontalChoiceRadioTopMarginRem: number;\n audioBlankTemplateMarginTopRem: number;\n audioBlankTemplateMarginBottomRem: number;\n audioInstructionsMaxWidthPx: number;\n narrowHorizontalChoiceMaxWidthPx: number;\n stimulusGridColumnGapRem: number;\n stimulusGridRowGapRem: number;\n stimulusSentenceMarginTopRem: number;\n stimulusChoicesMarginTopRem: number;\n tokenGridColumnGapRem: number;\n tokenGridRowGapRem: number;\n tokenTemplateMarginTopRem: number;\n tokenInlineTokenGapRem: number;\n tokenChoicesMarginTopRem: number;\n inlineGridColumnGapRem: number;\n inlineGridRowGapRem: number;\n inlineTemplateMarginTopRem: number;\n inlineChoicesMarginTopRem: number;\n};\n\n/** Baseline values tuned to match historical CQT visuals; override via model.layoutLimits. */\nexport const DEFAULT_LAYOUT_LIMITS: LayoutLimits = {\n blankStandaloneWidthRem: 7,\n blankWideWidthRem: 10,\n blankUnderlineWidthPx: 2,\n blankUnderlineWideWidthPx: 4,\n horizontalChoiceWidthPx: 170,\n horizontalChoiceWidthVw: 30,\n horizontalChoiceTileMinHeightRem: 11,\n horizontalChoiceContentMinHeightRem: 7.5,\n selectedImageMaxHeightRem: 4,\n choiceImageMaxHeightRem: 5,\n listenButtonSizePx: 128,\n stimulusMinColumnPx: 210,\n textMinColumnPx: 260,\n legendMaxChars: 120,\n choiceGroupGapRem: 0.5,\n choiceRowGapRem: 0.5,\n toggleButtonGapRem: 0.5,\n horizontalChoiceRadioTopMarginRem: 0.5,\n audioBlankTemplateMarginTopRem: 0.8,\n audioBlankTemplateMarginBottomRem: 1.8,\n audioInstructionsMaxWidthPx: 875,\n narrowHorizontalChoiceMaxWidthPx: 230,\n stimulusGridColumnGapRem: 2,\n stimulusGridRowGapRem: 0.7,\n stimulusSentenceMarginTopRem: 0.2,\n stimulusChoicesMarginTopRem: 0.9,\n tokenGridColumnGapRem: 1.5,\n tokenGridRowGapRem: 0.8,\n tokenTemplateMarginTopRem: 0.6,\n tokenInlineTokenGapRem: 0.35,\n tokenChoicesMarginTopRem: 0.2,\n inlineGridColumnGapRem: 1.5,\n inlineGridRowGapRem: 0.65,\n inlineTemplateMarginTopRem: 0.45,\n inlineChoicesMarginTopRem: 0.25,\n};\n","import { DEFAULT_LAYOUT_LIMITS } from '../shared/layoutLimits';\n\nexport { DEFAULT_LAYOUT_LIMITS };\n\n/** Token authors must include exactly once in `template` (HTML). */\nexport const BLANK_TOKEN = '{{blank}}';\n\nexport default {\n model: {\n id: '1',\n element: 'mc-populated-blank',\n prompt: '<p><strong>Demo prompt</strong></p>',\n promptEnabled: true,\n interactionMode: 'populate_blank' as const,\n layoutProfile: '',\n choiceLayout: '',\n layoutProfilePresets: {},\n layoutLimits: { ...DEFAULT_LAYOUT_LIMITS },\n audioButtonSkin: null,\n audioButtonSkinsByLocale: {},\n uiText: {\n answerChoices: 'Answer choices',\n selectedAnswerInSentence: 'blank',\n showCorrectAnswer: 'Show correct answer',\n hideCorrectAnswer: 'Hide correct answer',\n clickToEnableAutoplay: 'Click to enable audio autoplay',\n audioResourceUnavailable: 'Audio is enabled but no playable audio URL is configured.',\n transcriptLabel: 'Transcript',\n listenLabelEn: 'Listen',\n listenLabelEs: 'Escuchar',\n listenSilentAlt: 'Repeat instructions',\n listenPlayingAlt: 'Instructions are playing',\n listenSilentAltEs: 'Escuchar. Repetir las instrucciones.',\n listenPlayingAltEs: 'Escuchar. Estas son las instrucciones.',\n },\n sentenceHtml: '',\n template: `<p>The answer is ${BLANK_TOKEN}.</p>`,\n choiceMode: 'text' as const,\n choices: [\n { id: 'c1', labelHtml: '<p>Option A</p>' },\n { id: 'c2', labelHtml: '<p>Option B</p>' },\n { id: 'c3', labelHtml: '<p>Option C</p>' },\n ],\n correctChoiceId: 'c2',\n hasAudio: false,\n autoplayAudioEnabled: false,\n completeAudioEnabled: false,\n audioUrl: '',\n audioTranscript: '',\n locale: '',\n teacherInstructions: '',\n teacherInstructionsEnabled: false,\n },\n configuration: {\n prompt: {\n label: 'Prompt',\n settings: true,\n },\n },\n};\n","import defaults, { BLANK_TOKEN, DEFAULT_LAYOUT_LIMITS } from './defaults';\nimport type {\n McpbChoice,\n McpbQuestion,\n McpbSession,\n McpbEnv,\n McpbCorrectness,\n} from '../shared/types';\n\nconst isEmptyObject = (value: unknown): boolean =>\n !!value &&\n typeof value === 'object' &&\n !Array.isArray(value) &&\n Object.keys(value as Record<string, unknown>).length === 0;\n\nexport function countBlankTokens(template: string): number {\n if (!template) return 0;\n const re = /\\{\\{blank\\}\\}/g;\n return (template.match(re) || []).length;\n}\n\nexport const getCorrectness = (question: McpbQuestion, session: McpbSession): McpbCorrectness => {\n if (!session?.choiceId) {\n return 'unanswered';\n }\n const correct = question?.correctChoiceId || '';\n if (session.choiceId === correct) {\n return 'correct';\n }\n return 'incorrect';\n};\n\nexport const getPartialScore = (_question: McpbQuestion, session: McpbSession) => {\n if (!session || isEmptyObject(session) || !session.choiceId) {\n return 0;\n }\n return 1;\n};\n\nexport const outcome = (question: McpbQuestion, session: McpbSession, env: McpbEnv) =>\n new Promise((resolve) => {\n if (!session || isEmptyObject(session)) {\n resolve({\n score: 0,\n empty: true,\n traceLog: ['Student did not select any answers. Score is 0.'],\n });\n return;\n }\n\n session = normalizeSession(session);\n const correctness = getCorrectness(question, session);\n\n if (correctness === 'unanswered') {\n resolve({\n score: 0,\n empty: true,\n traceLog: ['Student did not select any answers. Score is 0.'],\n });\n return;\n }\n\n const score = correctness === 'correct' ? 1 : 0;\n const traceLog = [\n `Mode: ${env?.mode || 'unknown'}.`,\n `Student selected choice: ${session.choiceId}.`,\n `Correct choice: ${question?.correctChoiceId || 'none'}.`,\n `Final score: ${score}.`,\n ];\n resolve({ score, empty: false, traceLog });\n });\n\nexport const createDefaultModel = (model: McpbQuestion = {}) => ({\n ...defaults.model,\n ...model,\n layoutLimits: {\n ...DEFAULT_LAYOUT_LIMITS,\n ...(model?.layoutLimits || {}),\n },\n});\n\nexport const normalize = (question: McpbQuestion = {}) => createDefaultModel(question);\n\nexport const normalizeSession = (s: McpbSession): McpbSession => ({ ...s });\n\nconst shouldShuffleChoices = (question: McpbQuestion) => !!question?.shuffle;\n\nconst shouldLockChoices = (question: McpbQuestion, env: McpbEnv) => {\n if (question?.lockChoiceOrder) return true;\n if (env?.['@pie-element']?.lockChoiceOrder) return true;\n return env?.role === 'instructor';\n};\n\nfunction shuffleArray<T>(items: T[]): T[] {\n const out = [...items];\n for (let i = out.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [out[i], out[j]] = [out[j], out[i]];\n }\n return out;\n}\n\nconst getStoredShuffle = (session: McpbSession): string[] =>\n Array.isArray(session?.data?.shuffledValues)\n ? session.data.shuffledValues\n : Array.isArray(session?.shuffledValues)\n ? session.shuffledValues\n : [];\n\nconst applyShuffledValues = (\n choices: McpbChoice[],\n shuffledValues: string[],\n choiceKey: keyof McpbChoice\n) => {\n const orderedChoices = shuffledValues\n .map((value) => choices.find((choice) => choice?.[choiceKey] === value))\n .filter((c): c is McpbChoice => !!c);\n\n if (orderedChoices.length === choices.length) {\n return orderedChoices;\n }\n\n const orderedValues = new Set(orderedChoices.map((choice) => choice[choiceKey]));\n const leftovers = choices.filter((choice) => !orderedValues.has(choice?.[choiceKey]));\n return [...orderedChoices, ...leftovers];\n};\n\ntype UpdateSessionFn = (\n id: string,\n element: string,\n data: { shuffledValues: string[] }\n) => Promise<void>;\n\nconst getOrderedChoices = async (\n question: McpbQuestion,\n session: McpbSession,\n env: McpbEnv,\n updateSession?: UpdateSessionFn\n) => {\n const choices = Array.isArray(question?.choices) ? [...question.choices] : [];\n if (!choices.length || !shouldShuffleChoices(question)) {\n return choices;\n }\n\n if (shouldLockChoices(question, env || {})) {\n return choices;\n }\n\n const shuffledValues = getStoredShuffle(session);\n if (shuffledValues.length) {\n return applyShuffledValues(choices, shuffledValues, 'id');\n }\n\n const shuffledChoices = shuffleArray(choices);\n\n if (updateSession && typeof updateSession === 'function' && session?.id && session?.element) {\n const shuffledIds = shuffledChoices.map((choice) => choice?.id).filter(Boolean);\n if (shuffledIds.length) {\n await updateSession(session.id, session.element, { shuffledValues: shuffledIds });\n }\n }\n\n return shuffledChoices;\n};\n\nexport const model = async (\n question: McpbQuestion,\n session: McpbSession | null,\n env: McpbEnv | null,\n updateSession?: UpdateSessionFn\n) => {\n const safeSession: McpbSession = session || {};\n const safeEnv: McpbEnv = env || {};\n const normalizedQuestion = normalize(question);\n const choices = await getOrderedChoices(normalizedQuestion, safeSession, safeEnv, updateSession);\n\n const out: Record<string, unknown> = {\n prompt: normalizedQuestion.promptEnabled ? normalizedQuestion.prompt : null,\n interactionMode: normalizedQuestion.interactionMode || 'populate_blank',\n layoutProfile: normalizedQuestion.layoutProfile || '',\n choiceLayout: normalizedQuestion.choiceLayout || '',\n layoutProfilePresets:\n normalizedQuestion.layoutProfilePresets &&\n typeof normalizedQuestion.layoutProfilePresets === 'object'\n ? normalizedQuestion.layoutProfilePresets\n : {},\n layoutLimits: normalizedQuestion.layoutLimits || { ...DEFAULT_LAYOUT_LIMITS },\n audioButtonSkin:\n normalizedQuestion.audioButtonSkin && typeof normalizedQuestion.audioButtonSkin === 'object'\n ? normalizedQuestion.audioButtonSkin\n : null,\n audioButtonSkinsByLocale:\n normalizedQuestion.audioButtonSkinsByLocale &&\n typeof normalizedQuestion.audioButtonSkinsByLocale === 'object'\n ? normalizedQuestion.audioButtonSkinsByLocale\n : {},\n uiText:\n normalizedQuestion.uiText && typeof normalizedQuestion.uiText === 'object'\n ? normalizedQuestion.uiText\n : {},\n sentenceHtml: normalizedQuestion.sentenceHtml || null,\n template: normalizedQuestion.template,\n choiceMode: normalizedQuestion.choiceMode,\n choices,\n hasAudio: normalizedQuestion.hasAudio,\n autoplayAudioEnabled: !!normalizedQuestion.autoplayAudioEnabled,\n completeAudioEnabled: !!normalizedQuestion.completeAudioEnabled,\n audioUrl: normalizedQuestion.hasAudio ? normalizedQuestion.audioUrl : null,\n audioTranscript: normalizedQuestion.hasAudio ? normalizedQuestion.audioTranscript : null,\n customType: normalizedQuestion.customType || '',\n useFeatureButtonAudio:\n typeof normalizedQuestion.useFeatureButtonAudio === 'boolean'\n ? normalizedQuestion.useFeatureButtonAudio\n : undefined,\n locale: normalizedQuestion.locale || '',\n disabled: safeEnv.mode !== 'gather',\n mode: safeEnv.mode,\n };\n\n if (safeEnv.mode === 'evaluate') {\n const correctness = getCorrectness(normalizedQuestion, safeSession);\n out.correctness = correctness;\n out.responseCorrect = correctness === 'correct';\n out.correctChoiceId = normalizedQuestion.correctChoiceId;\n }\n\n if (safeEnv.role === 'instructor' && (safeEnv.mode === 'view' || safeEnv.mode === 'evaluate')) {\n out.teacherInstructions = normalizedQuestion.teacherInstructionsEnabled\n ? normalizedQuestion.teacherInstructions\n : null;\n } else {\n out.teacherInstructions = null;\n }\n\n return out;\n};\n\nexport const createCorrectResponseSession = (question: McpbQuestion, env: McpbEnv) => {\n return new Promise((resolve) => {\n if (env.mode !== 'evaluate' && env.role === 'instructor') {\n resolve({\n id: '1',\n element: 'mc-populated-blank',\n choiceId: question?.correctChoiceId || '',\n });\n } else {\n resolve(null);\n }\n });\n};\n\nexport const validate = (question: McpbQuestion = {}, _config: Record<string, unknown> = {}) => {\n const errors: Record<string, string> = {};\n\n if (question.promptEnabled) {\n const p = question.prompt?.trim() || '';\n if (!p || p === '<p></p>') {\n errors.prompt = 'Prompt is required when prompt is enabled';\n }\n }\n\n const interactionMode = question.interactionMode || 'populate_blank';\n const template = question.template || '';\n const n = countBlankTokens(template);\n if (interactionMode === 'audio_mc_only') {\n if (n > 0) {\n errors.template = `Template cannot contain ${BLANK_TOKEN} in audio-only mode`;\n }\n } else if (interactionMode === 'populate_blank') {\n if (n === 0) {\n errors.template = `Template must contain exactly one ${BLANK_TOKEN} placeholder`;\n } else if (n > 1) {\n errors.template = `Template must contain only one ${BLANK_TOKEN} placeholder`;\n }\n } else {\n errors.interactionMode = 'Unknown interaction mode';\n }\n\n const choices = Array.isArray(question.choices) ? question.choices : [];\n if (choices.length < 2) {\n errors.choices = 'At least two choices are required';\n }\n\n const mode = question.choiceMode || 'text';\n for (let i = 0; i < choices.length; i++) {\n const c = choices[i];\n if (!c?.id) {\n errors.choices = `Choice ${i + 1} is missing an id`;\n break;\n }\n if (mode === 'text') {\n const lbl = (c.labelHtml || '').trim();\n if (!lbl || lbl === '<p></p>') {\n errors.choices = `Choice ${i + 1} needs label text`;\n break;\n }\n } else {\n if (!c.imageUrl?.trim()) {\n errors.choices = `Choice ${i + 1} needs an image URL`;\n break;\n }\n if (!c.imageAlt?.trim()) {\n errors.choices = `Choice ${i + 1} needs image alt text`;\n break;\n }\n }\n }\n\n const correct = question.correctChoiceId;\n if (!correct || !choices.some((c) => c.id === correct)) {\n errors.correctChoiceId = 'Correct choice must match one of the choice ids';\n }\n\n if (question.hasAudio) {\n const hasAudioUrl = !!question.audioUrl?.trim();\n if (!hasAudioUrl) {\n errors.audioUrl = 'A playable audio URL is required when audio is enabled';\n }\n }\n\n const limits = question?.layoutLimits;\n if (limits && typeof limits === 'object') {\n const numericLimitKeys = [\n 'blankStandaloneWidthRem',\n 'blankWideWidthRem',\n 'blankUnderlineWidthPx',\n 'blankUnderlineWideWidthPx',\n 'horizontalChoiceWidthPx',\n 'horizontalChoiceWidthVw',\n 'horizontalChoiceTileMinHeightRem',\n 'horizontalChoiceContentMinHeightRem',\n 'selectedImageMaxHeightRem',\n 'choiceImageMaxHeightRem',\n 'listenButtonSizePx',\n 'stimulusMinColumnPx',\n 'textMinColumnPx',\n 'legendMaxChars',\n 'choiceGroupGapRem',\n 'choiceRowGapRem',\n 'toggleButtonGapRem',\n 'horizontalChoiceRadioTopMarginRem',\n 'audioBlankTemplateMarginTopRem',\n 'audioBlankTemplateMarginBottomRem',\n 'audioInstructionsMaxWidthPx',\n 'narrowHorizontalChoiceMaxWidthPx',\n 'stimulusGridColumnGapRem',\n 'stimulusGridRowGapRem',\n 'stimulusSentenceMarginTopRem',\n 'stimulusChoicesMarginTopRem',\n 'tokenGridColumnGapRem',\n 'tokenGridRowGapRem',\n 'tokenTemplateMarginTopRem',\n 'tokenInlineTokenGapRem',\n 'tokenChoicesMarginTopRem',\n 'inlineGridColumnGapRem',\n 'inlineGridRowGapRem',\n 'inlineTemplateMarginTopRem',\n 'inlineChoicesMarginTopRem',\n ] as const;\n for (const key of numericLimitKeys) {\n if (limits[key] === undefined || limits[key] === null) continue;\n const value = Number(limits[key]);\n if (!Number.isFinite(value) || value <= 0) {\n errors.layoutLimits = `${key} must be a positive number when provided`;\n break;\n }\n }\n }\n\n return errors;\n};\n"],"mappings":"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"}
|
|
@@ -15,4 +15,3 @@ export interface ChoiceCorrectnessParams {
|
|
|
15
15
|
* (incorrect badge) rather than triggering the two-badge wrong-answer path.
|
|
16
16
|
*/
|
|
17
17
|
export declare function computeChoiceCorrectness(params: ChoiceCorrectnessParams): Map<string, 'correct' | 'incorrect'>;
|
|
18
|
-
//# sourceMappingURL=computeChoiceCorrectness.d.ts.map
|
package/dist/delivery/index.d.ts
CHANGED