@intellectif/lk-react 3.0.0 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/README.md +7 -2
  2. package/dist/{WrittenResponse-BHhP936i.d.ts → WrittenResponse-Dkg7FUt-.d.ts} +1 -1
  3. package/dist/{WrittenResponse-B50EjVR0.d.cts → WrittenResponse-DqQ0NjPK.d.cts} +1 -1
  4. package/dist/chunk-3B4ACY4K.cjs +249 -0
  5. package/dist/chunk-3B4ACY4K.cjs.map +1 -0
  6. package/dist/{chunk-3X7MYAFT.js → chunk-3DNJDP73.js} +11 -9
  7. package/dist/chunk-3DNJDP73.js.map +1 -0
  8. package/dist/chunk-4HZ7LQIH.cjs +40 -0
  9. package/dist/chunk-4HZ7LQIH.cjs.map +1 -0
  10. package/dist/{chunk-ZVFWJTT4.js → chunk-5SYL5CJ2.js} +10 -28
  11. package/dist/chunk-5SYL5CJ2.js.map +1 -0
  12. package/dist/{chunk-UXO6KYSZ.cjs → chunk-67RIIDZX.cjs} +17 -15
  13. package/dist/chunk-67RIIDZX.cjs.map +1 -0
  14. package/dist/{chunk-AEQQ7VPF.js → chunk-67WDTQMG.js} +9 -4
  15. package/dist/chunk-67WDTQMG.js.map +1 -0
  16. package/dist/{chunk-7MW7HGOA.cjs → chunk-6COTYW77.cjs} +15 -10
  17. package/dist/chunk-6COTYW77.cjs.map +1 -0
  18. package/dist/chunk-6F4X2NKL.js +54 -0
  19. package/dist/chunk-6F4X2NKL.js.map +1 -0
  20. package/dist/chunk-GB5URWM4.js +38 -0
  21. package/dist/chunk-GB5URWM4.js.map +1 -0
  22. package/dist/chunk-NBFTCGQ5.js +247 -0
  23. package/dist/chunk-NBFTCGQ5.js.map +1 -0
  24. package/dist/chunk-NEWGUDA5.cjs +49 -0
  25. package/dist/chunk-NEWGUDA5.cjs.map +1 -0
  26. package/dist/{chunk-QHOV2A6M.cjs → chunk-PGEG7UZJ.cjs} +2 -34
  27. package/dist/chunk-PGEG7UZJ.cjs.map +1 -0
  28. package/dist/chunk-UQ3BBEIT.js +47 -0
  29. package/dist/chunk-UQ3BBEIT.js.map +1 -0
  30. package/dist/{chunk-W6BH2YMZ.cjs → chunk-WCVD5LVG.cjs} +16 -34
  31. package/dist/chunk-WCVD5LVG.cjs.map +1 -0
  32. package/dist/components/ActivitySequence.cjs +8 -6
  33. package/dist/components/ActivitySequence.d.cts +87 -9
  34. package/dist/components/ActivitySequence.d.ts +87 -9
  35. package/dist/components/ActivitySequence.js +7 -5
  36. package/dist/components/FillInTheBlanks.cjs +4 -3
  37. package/dist/components/FillInTheBlanks.d.cts +1 -1
  38. package/dist/components/FillInTheBlanks.d.ts +1 -1
  39. package/dist/components/FillInTheBlanks.js +3 -2
  40. package/dist/components/MultipleChoice.cjs +4 -3
  41. package/dist/components/MultipleChoice.d.cts +1 -1
  42. package/dist/components/MultipleChoice.d.ts +1 -1
  43. package/dist/components/MultipleChoice.js +3 -2
  44. package/dist/components/StimulusPanel.cjs +13 -0
  45. package/dist/components/StimulusPanel.cjs.map +1 -0
  46. package/dist/components/StimulusPanel.d.cts +30 -0
  47. package/dist/components/StimulusPanel.d.ts +30 -0
  48. package/dist/components/StimulusPanel.js +4 -0
  49. package/dist/components/StimulusPanel.js.map +1 -0
  50. package/dist/components/WrittenResponse.cjs +4 -3
  51. package/dist/components/WrittenResponse.d.cts +3 -3
  52. package/dist/components/WrittenResponse.d.ts +3 -3
  53. package/dist/components/WrittenResponse.js +3 -2
  54. package/dist/index.cjs +36 -26
  55. package/dist/index.cjs.map +1 -1
  56. package/dist/index.d.cts +3 -2
  57. package/dist/index.d.ts +3 -2
  58. package/dist/index.js +12 -7
  59. package/dist/index.js.map +1 -1
  60. package/dist/theme/skin.css +49 -0
  61. package/dist/{types-CNmjqD6M.d.cts → types-CrURyd9-.d.cts} +51 -3
  62. package/dist/{types-CNmjqD6M.d.ts → types-CrURyd9-.d.ts} +51 -3
  63. package/package.json +15 -4
  64. package/dist/chunk-3X7MYAFT.js.map +0 -1
  65. package/dist/chunk-7MW7HGOA.cjs.map +0 -1
  66. package/dist/chunk-AEQQ7VPF.js.map +0 -1
  67. package/dist/chunk-BGWXN44S.js +0 -152
  68. package/dist/chunk-BGWXN44S.js.map +0 -1
  69. package/dist/chunk-HO3AC3WQ.cjs +0 -154
  70. package/dist/chunk-HO3AC3WQ.cjs.map +0 -1
  71. package/dist/chunk-QHOV2A6M.cjs.map +0 -1
  72. package/dist/chunk-UIGIYYGY.js +0 -85
  73. package/dist/chunk-UIGIYYGY.js.map +0 -1
  74. package/dist/chunk-UXO6KYSZ.cjs.map +0 -1
  75. package/dist/chunk-W6BH2YMZ.cjs.map +0 -1
  76. package/dist/chunk-ZVFWJTT4.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/MultipleChoice/MultipleChoice.tsx","../src/components/MultipleChoice/index.tsx"],"names":["useMemo","isDevelopment","validateActivity","ActivitySchemaError","useRef","useActivityState","useState","useEffect","randomSessionId","seededShuffle","score","xAPIBuilder","ANONYMOUS_ACTOR","objectIdFor","xapiDefinitionFor","jsxs","jsx","ActivityMedia","FeedbackRegion","MultipleChoice","ActivityErrorBoundary"],"mappings":"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","file":"chunk-WCVD5LVG.cjs","sourcesContent":["'use client';\n\nimport {\n ActivitySchemaError,\n type ItemOutcome,\n type LearnerResponse,\n type MultipleChoiceData,\n type MultipleChoiceLearnerResponse,\n type MultipleChoiceOption,\n type ScoringDetail,\n score,\n seededShuffle,\n validateActivity,\n xAPIBuilder,\n xapiDefinitionFor,\n} from '@intellectif/lk-core';\nimport { type CSSProperties, useEffect, useMemo, useRef, useState } from 'react';\nimport { useActivityState } from '../../hooks/useActivityState.js';\nimport { ANONYMOUS_ACTOR, isDevelopment, objectIdFor, randomSessionId } from '../_internal.js';\nimport { ActivityMedia } from '../shared/ActivityMedia.js';\nimport { FeedbackRegion } from '../shared/FeedbackRegion.js';\nimport type { ActivityProps } from '../types.js';\n\n/**\n * Selected option ids carried by a learner response. Any other response shape\n * (a caller wiring the wrong item's state through `value`) reads as \"nothing\n * selected\" rather than throwing mid-exam.\n */\nfunction selectionOf(response: LearnerResponse | undefined): string[] {\n return response?.type === 'multiple-choice' ? response.selectedOptionIds : [];\n}\n\n/**\n * Whether an option is part of the correct answer, derived from the SERVER's\n * outcome — review mode never holds an answer key of its own.\n * {@link ScoringDetail.outcome} states this unambiguously. For 0.2-era details\n * that carry only the deprecated `correct` flag (which means \"the learner\n * ACTED correctly on this option\", not \"this option is the answer\") the fact\n * is still recoverable, because we know whether the learner selected it:\n * `isCorrect = wasSelected ? correct : !correct`.\n */\nfunction isAnswerOption(detail: ScoringDetail, wasSelected: boolean): boolean {\n switch (detail.outcome) {\n case 'correct':\n case 'incorrect-omission':\n return true;\n case 'incorrect':\n case 'correct-omission':\n return false;\n default:\n return wasSelected ? detail.correct : !detail.correct;\n }\n}\n\n/** Announcement for `review` mode, built only from the server-supplied outcome. */\nfunction reviewAnnouncement(outcome: ItemOutcome | undefined): string | null {\n if (outcome === undefined) {\n return null;\n }\n if (outcome.status === 'scored') {\n const overall = outcome.feedback;\n return `Score ${Math.round(outcome.score * 100)}%. ${\n outcome.passed ? 'Passed.' : 'Not passed.'\n }${overall ? ` ${overall}` : ''}`;\n }\n if (outcome.status === 'deferred') {\n // Never \"0%\": ungraded is not the same as wrong.\n return 'Not graded yet.';\n }\n return null;\n}\n\nexport interface MultipleChoiceProps extends ActivityProps<MultipleChoiceData> {\n /**\n * Seed for the deterministic option shuffle. Supply one (e.g. the attempt\n * id) to make the shuffled order reproducible server-side, stable across\n * page reloads, and identical between SSR and hydration. When absent, a\n * random per-mount session seed is used (order stable within the mount\n * only — the v1 behaviour).\n */\n shuffleSeed?: string;\n}\n\nexport function MultipleChoice({\n data,\n onComplete,\n onSubmit,\n value,\n defaultValue,\n onChange,\n renderMode = 'practice',\n outcome,\n sanitizeHtml,\n onInteraction,\n theme,\n locale,\n disabled,\n shuffleSeed,\n}: MultipleChoiceProps) {\n // Dev-only boundary validation (Req 2.3). Throwing during render lets\n // ActivityErrorBoundary catch it. Memoised so it only re-runs on data change.\n const devError = useMemo(() => {\n if (!isDevelopment()) {\n return null;\n }\n // A `redact()` projection cannot satisfy the full content schema — the\n // answer key is gone by design — and must not be checked against the\n // strict redacted schema either, since a `reveal: 'after-submit'`\n // projection legitimately carries answer-key fields for review renders.\n if (data.redacted === true) {\n return null;\n }\n const result = validateActivity('multiple-choice', data);\n return result.success ? null : new ActivitySchemaError('multiple-choice', result.errors);\n }, [data]);\n\n // Lazily created only when shuffling without a caller seed: avoids calling\n // crypto.randomUUID (absent on non-secure http origins) unless needed.\n const sessionIdRef = useRef<string | null>(null);\n const { state, start, complete, getTimeSpent, reset } = useActivityState();\n // Uncontrolled state. `defaultValue` seeds the mount only (React convention);\n // to re-seed later, remount with a `key` or drive the component with `value`.\n const [internalSelection, setInternalSelection] = useState<string[]>(() =>\n selectionOf(defaultValue),\n );\n const [summary, setSummary] = useState<string | null>(null);\n\n // Reset on data-prop CHANGE (Req 3.7). The identity guard makes the mount\n // run a no-op, which it always was before `defaultValue` existed — without\n // it this effect would wipe the seed immediately after the first render.\n // (It also makes the reset StrictMode-safe: a remount with unchanged data\n // no longer discards the learner's selection.)\n // Clears to empty rather than back to `defaultValue`: carrying a stale\n // answer into a different question is the one failure mode a summative\n // component must never have.\n const lastDataRef = useRef(data);\n useEffect(() => {\n if (lastDataRef.current === data) {\n return;\n }\n lastDataRef.current = data;\n setInternalSelection([]);\n setSummary(null);\n reset();\n }, [data, reset]);\n\n const displayedOptions = useMemo<MultipleChoiceOption[]>(() => {\n if (!data.shuffle) {\n return [...data.options];\n }\n // biome-ignore lint/suspicious/noAssignInExpressions: sanctioned lazy ref initialization\n const seedSource = shuffleSeed ?? (sessionIdRef.current ??= randomSessionId());\n // The seed string is unchanged from when the algorithm lived in this file,\n // so an order a consumer recorded against a seed still reproduces.\n return seededShuffle(data.options, `${seedSource}:${data.id}`);\n }, [data, shuffleSeed]);\n\n // Per-option correctness for `review`, indexed by option id. Null unless the\n // caller supplied a SCORED outcome — the only source of truth this mode has.\n const reviewDetails = useMemo(() => {\n if (renderMode !== 'review' || outcome === undefined || outcome.status !== 'scored') {\n return null;\n }\n return new Map(outcome.details.map((detail) => [detail.itemId, detail]));\n }, [renderMode, outcome]);\n\n // All hooks are called before these throws, so hook order stays stable.\n if (devError) {\n throw devError;\n }\n // Practice grades locally, which a redacted projection cannot support:\n // `score()` would throw from the submit handler — where no error boundary\n // can catch it — AFTER the learner has answered. Fail loudly at render\n // instead, in production too. Wiring an exam item into the self-grading\n // mode is precisely the accident `renderMode` exists to prevent.\n if (data.redacted === true && renderMode === 'practice') {\n throw new Error(\n `Multiple Choice \"${data.id}\" received redacted activity data in renderMode \"practice\", ` +\n 'which grades locally and has no answer key to grade against. ' +\n 'Render redacted data with renderMode=\"exam\" (server grades) or \"review\" (pass `outcome`).',\n );\n }\n\n const isSingle = data.mode === 'single';\n const isExam = renderMode === 'exam';\n const isReview = renderMode === 'review';\n const submitted = state === 'completed';\n const inactive = disabled === true || submitted || isReview;\n const isControlled = value !== undefined;\n const selected = isControlled ? selectionOf(value) : internalSelection;\n /**\n * Whether correctness and authored feedback may be shown. Practice earns it\n * by grading locally after submit; review shows what the server already\n * graded. Exam never reveals anything — not before, not after submit.\n */\n const reveal = isReview || (renderMode === 'practice' && submitted);\n\n const fireInteraction = (\n type: 'option-selected' | 'option-deselected' | 'submitted',\n payload: Record<string, unknown>,\n ): void => {\n onInteraction?.({ type, activityId: data.id, timestamp: Date.now(), payload });\n };\n\n /** Single funnel for every response change: owns state only when uncontrolled. */\n const emitChange = (selectedOptionIds: string[]): void => {\n if (!isControlled) {\n setInternalSelection(selectedOptionIds);\n }\n onChange?.({ type: 'multiple-choice', selectedOptionIds });\n };\n\n const selectSingle = (optionId: string): void => {\n if (inactive) {\n return;\n }\n if (state === 'idle') {\n start();\n }\n emitChange([optionId]);\n fireInteraction('option-selected', { optionId });\n };\n\n const toggleMulti = (optionId: string, checked: boolean): void => {\n if (inactive) {\n return;\n }\n if (state === 'idle') {\n start();\n }\n emitChange(checked ? [...selected, optionId] : selected.filter((id) => id !== optionId));\n fireInteraction(checked ? 'option-selected' : 'option-deselected', { optionId });\n };\n\n const handleSubmit = (event: React.FormEvent): void => {\n event.preventDefault();\n if (inactive) {\n return;\n }\n const response: MultipleChoiceLearnerResponse = {\n type: 'multiple-choice',\n selectedOptionIds: selected,\n };\n // Always first, and before anything that can throw: an exam runner must be\n // able to persist the raw response no matter what happens after.\n onSubmit?.(response);\n\n if (isExam) {\n // No score(), no answer key read, no onComplete, no xAPI — the server\n // grades. The announcement deliberately carries no correctness signal.\n complete();\n setSummary('Answer submitted.');\n fireInteraction('submitted', { selectedOptionIds: selected });\n return;\n }\n\n const scoringResult = score('multiple-choice', data as MultipleChoiceData, response);\n complete();\n const timeSpent = getTimeSpent();\n const xapiStatement = xAPIBuilder.buildAnsweredStatement({\n actor: ANONYMOUS_ACTOR,\n object: {\n id: objectIdFor(data.id),\n name: { [data.locale ?? 'en-US']: data.title },\n // Activity-type IRI, interaction type and correct-responses pattern\n // come from the REGISTERED descriptor, so a consumer-registered type\n // gets correct interop without touching this component.\n ...xapiDefinitionFor(data),\n choices: data.options.map((option) => ({\n id: option.id,\n description: { [data.locale ?? 'en-US']: option.text },\n })),\n },\n scoringResult,\n timeSpentMs: timeSpent,\n response: selected.join(','),\n });\n onComplete?.({\n score: scoringResult.score,\n maxScore: scoringResult.maxScore,\n passed: scoringResult.passed,\n timeSpent,\n xapiStatement,\n });\n // Core selects the authored overall feedback on `passed` (B3 fix).\n const overall = scoringResult.feedback;\n setSummary(\n `Answer submitted. Score ${Math.round(scoringResult.score * 100)}%. ${\n scoringResult.passed ? 'Passed.' : 'Not passed.'\n }${overall ? ` ${overall}` : ''}`,\n );\n fireInteraction('submitted', {\n selectedOptionIds: selected,\n score: scoringResult.score,\n });\n };\n\n const questionId = `${data.id}-question`;\n // Rich text renders ONLY through a caller-supplied sanitiser; without one we\n // fall back to the plain-text field, escaped by React (types.ts HtmlSanitizer).\n const questionHtml =\n sanitizeHtml !== undefined && data.questionHtml !== undefined\n ? sanitizeHtml(data.questionHtml)\n : null;\n\n const optionList = displayedOptions.map((option) => {\n const checked = selected.includes(option.id);\n // `data-correct` means \"this option is part of the correct answer\".\n let correctness: string | undefined;\n if (isReview) {\n const detail = reviewDetails?.get(option.id);\n correctness = detail === undefined ? undefined : String(isAnswerOption(detail, checked));\n } else if (reveal) {\n correctness = String(option.isCorrect);\n }\n return (\n <label key={option.id} className=\"lk-mc-option\" data-correct={correctness}>\n <input\n type={isSingle ? 'radio' : 'checkbox'}\n name={isSingle ? `${data.id}-options` : undefined}\n value={option.id}\n checked={checked}\n disabled={inactive}\n aria-disabled={inactive || undefined}\n onChange={(e) =>\n isSingle ? selectSingle(option.id) : toggleMulti(option.id, e.target.checked)\n }\n />\n <span>{option.text}</span>\n {reveal && option.feedback ? (\n <span className=\"lk-mc-option-feedback\" role=\"note\">\n {option.feedback}\n </span>\n ) : null}\n </label>\n );\n });\n\n return (\n <div className=\"lk-mc\" lang={locale} style={theme as CSSProperties | undefined}>\n {data.media ? <ActivityMedia media={data.media} /> : null}\n <form onSubmit={handleSubmit}>\n <fieldset disabled={inactive}>\n {questionHtml === null ? (\n <legend id={questionId}>{data.question}</legend>\n ) : (\n <legend\n id={questionId}\n // biome-ignore lint/security/noDangerouslySetInnerHtml: HTML is the output of the caller-supplied sanitizeHtml (types.ts HtmlSanitizer contract)\n dangerouslySetInnerHTML={{ __html: questionHtml }}\n />\n )}\n {/*\n single: an explicit radiogroup is meaningful (fieldset's implicit\n role is `group`, not `radiogroup`). multi: the fieldset + legend\n already provide a named group — an explicit role=\"group\" here would\n be a redundant, duplicate same-named group in the a11y tree, so we\n use a plain layout div. (Refines the design ARIA sketch.)\n */}\n {isSingle ? (\n <div role=\"radiogroup\" aria-labelledby={questionId}>\n {optionList}\n </div>\n ) : (\n <div>{optionList}</div>\n )}\n {/* review is read-only: there is nothing left to submit. */}\n {isReview ? null : (\n <button type=\"submit\" disabled={inactive}>\n Submit\n </button>\n )}\n </fieldset>\n </form>\n <FeedbackRegion id={`${data.id}-feedback`}>\n {isReview ? reviewAnnouncement(outcome) : summary}\n </FeedbackRegion>\n </div>\n );\n}\n","'use client';\n\nimport { ActivityErrorBoundary } from '../ActivityErrorBoundary.js';\nimport {\n MultipleChoice as MultipleChoiceCore,\n type MultipleChoiceProps,\n} from './MultipleChoice.js';\n\nexport type { MultipleChoiceProps } from './MultipleChoice.js';\n\n/**\n * Public Multiple Choice activity: the core component wrapped in\n * `ActivityErrorBoundary` so a render failure (incl. the dev schema-validation\n * throw) degrades to an accessible fallback instead of crashing the host.\n */\nexport function MultipleChoice(props: MultipleChoiceProps) {\n return (\n <ActivityErrorBoundary activityTitle={props.data?.title}>\n <MultipleChoiceCore {...props} />\n </ActivityErrorBoundary>\n );\n}\n"]}
@@ -1,17 +1,19 @@
1
1
  'use strict';
2
2
 
3
- var chunkHO3AC3WQ_cjs = require('../chunk-HO3AC3WQ.cjs');
4
- require('../chunk-W6BH2YMZ.cjs');
5
- require('../chunk-UXO6KYSZ.cjs');
6
- require('../chunk-7MW7HGOA.cjs');
7
- require('../chunk-QHOV2A6M.cjs');
3
+ var chunk3B4ACY4K_cjs = require('../chunk-3B4ACY4K.cjs');
4
+ require('../chunk-WCVD5LVG.cjs');
5
+ require('../chunk-67RIIDZX.cjs');
6
+ require('../chunk-6COTYW77.cjs');
7
+ require('../chunk-PGEG7UZJ.cjs');
8
+ require('../chunk-NEWGUDA5.cjs');
9
+ require('../chunk-4HZ7LQIH.cjs');
8
10
  require('../chunk-HD2AIQRD.cjs');
9
11
 
10
12
 
11
13
 
12
14
  Object.defineProperty(exports, "ActivitySequence", {
13
15
  enumerable: true,
14
- get: function () { return chunkHO3AC3WQ_cjs.ActivitySequence; }
16
+ get: function () { return chunk3B4ACY4K_cjs.ActivitySequence; }
15
17
  });
16
18
  //# sourceMappingURL=ActivitySequence.cjs.map
17
19
  //# sourceMappingURL=ActivitySequence.cjs.map
@@ -1,7 +1,7 @@
1
- import { ActivityData, ActivityResult, InteractionEvent, ThemeTokens } from '@intellectif/lk-core';
1
+ import { SequenceEntry, ActivityResult, LearnerResponse, InteractionEvent, ThemeTokens } from '@intellectif/lk-core';
2
2
  import { ComponentType } from 'react';
3
- import { A as ActivityProps, R as RenderMode } from '../types-CNmjqD6M.cjs';
4
- import { a as WrittenResponseSubmission } from '../WrittenResponse-B50EjVR0.cjs';
3
+ import { A as ActivityProps, b as RenderableActivity, R as RenderMode, H as HtmlSanitizer } from '../types-CrURyd9-.cjs';
4
+ import { a as WrittenResponseSubmission } from '../WrittenResponse-DqQ0NjPK.cjs';
5
5
 
6
6
  /**
7
7
  * What one finished slot in a sequence produced. Two kinds, because two kinds
@@ -11,15 +11,30 @@ import { a as WrittenResponseSubmission } from '../WrittenResponse-B50EjVR0.cjs'
11
11
  */
12
12
  type SequenceItemOutcome = {
13
13
  kind: 'scored';
14
+ /** Presented position. */
14
15
  index: number;
16
+ /** Slot identity from `flattenSequence` — stable under shuffling; the `slotId` to score with. */
17
+ slotId: string;
15
18
  activityId: string;
16
19
  result: ActivityResult;
17
20
  } | {
18
21
  kind: 'submitted';
19
22
  index: number;
23
+ slotId: string;
20
24
  activityId: string;
21
25
  /** Ungraded submission; the grade arrives asynchronously. */
22
26
  submission: WrittenResponseSubmission;
27
+ } | {
28
+ kind: 'responded';
29
+ index: number;
30
+ slotId: string;
31
+ activityId: string;
32
+ /**
33
+ * The raw answer, with no grade of any kind. This is what an `exam` slot
34
+ * produces: the client is forbidden to score, so a response is all there
35
+ * is until the server grades it.
36
+ */
37
+ response: LearnerResponse;
23
38
  };
24
39
  /**
25
40
  * A component that can render one activity inside a sequence. Register one per
@@ -28,23 +43,57 @@ type SequenceItemOutcome = {
28
43
  */
29
44
  type ActivityRenderer = ComponentType<ActivityProps>;
30
45
  interface ActivitySequenceProps {
31
- /** The ordered set of activities to present, one at a time. */
32
- activities: ActivityData[];
46
+ /**
47
+ * The ordered set of entries to present, one question at a time: loose
48
+ * activities, and item groups — a shared passage, recording or image with
49
+ * the questions that refer to it. A group's stimulus stays on screen
50
+ * alongside each of its questions.
51
+ *
52
+ * Accepts `redact()` projections. For data straight off a server, pass it
53
+ * through `asRenderableSequence()` — see that helper for why a cast is
54
+ * unavoidable there — and set `renderMode="exam"`.
55
+ */
56
+ activities: readonly SequenceEntry<RenderableActivity>[];
33
57
  /**
34
58
  * Renderers for activity types beyond the built-ins, keyed by `data.type`.
35
59
  * A key matching a built-in overrides it, so a consumer can replace the
36
60
  * bundled renderer without forking the sequencer.
37
61
  */
38
62
  renderers?: Readonly<Record<string, ActivityRenderer>>;
39
- /** Called whenever an individual activity is scored at submit time. */
40
- onActivityComplete?: (result: ActivityResult, index: number) => void;
63
+ /**
64
+ * Called whenever an individual activity is scored at submit time — the
65
+ * incremental persist hook.
66
+ *
67
+ * `slotId` is the identity to store the result against, NOT `index`.
68
+ * `index` is where the question was PRESENTED, which is not stable: it moves
69
+ * under shuffling, and it already differs from the slot identity whenever a
70
+ * group is present (the second entry of a sequence is presented at index 1
71
+ * but is slot `"1.0"` if it is a group's first question). `composeAssessmentScore`
72
+ * scores by `slotId`, so persisting `index` cannot be reconciled with it.
73
+ */
74
+ onActivityComplete?: (result: ActivityResult, index: number, slotId: string) => void;
75
+ /**
76
+ * Called on every submit with the learner's raw response and the identity of
77
+ * the slot that produced it — before any grading, in every render mode.
78
+ *
79
+ * **This is the only response channel an `exam` sequence has.** In `exam`
80
+ * mode the components never grade, so `onActivityComplete` cannot fire and
81
+ * `onComplete` never will; without this prop nothing a learner submitted
82
+ * would reach the consumer at all. Persist `response` against `slotId`.
83
+ */
84
+ onSubmit?: (response: LearnerResponse, slot: {
85
+ slotId: string;
86
+ index: number;
87
+ activityId: string;
88
+ }) => void;
41
89
  /**
42
90
  * Called once every activity has been completed, with the scored results.
43
91
  *
44
92
  * Fires only when EVERY item produced a score. A set containing a
45
93
  * deferred-graded activity (a written response) can never satisfy that, so
46
94
  * use `onFinished` for mixed sets — it is the general completion signal and
47
- * reports both kinds of outcome.
95
+ * reports both kinds of outcome. It also carries `slotId` per item, which
96
+ * this callback's bare array cannot.
48
97
  */
49
98
  onComplete?: (results: ActivityResult[]) => void;
50
99
  /**
@@ -57,6 +106,30 @@ interface ActivitySequenceProps {
57
106
  onInteraction?: (event: InteractionEvent) => void;
58
107
  /** Forwarded to each activity. `exam` and `review` disable local scoring. */
59
108
  renderMode?: RenderMode;
109
+ /**
110
+ * `entries` shuffles the top-level entries; a group moves as one block, and
111
+ * the order INSIDE a group follows the group's own `shuffle` setting.
112
+ * Default `none`: authored order.
113
+ */
114
+ shuffle?: 'none' | 'entries';
115
+ /**
116
+ * Seed for every shuffle in this sequence (`shuffle: 'entries'` and any
117
+ * group with `shuffle: 'within-group'`). Supply the attempt id, so the
118
+ * server's `flattenSequence(entries, { seed })` derives the same order this
119
+ * pager shows.
120
+ *
121
+ * **Required in `exam` and `review` mode** — omitting it throws. An order
122
+ * nobody can reproduce cannot be reconciled with a recorded attempt, and
123
+ * failing at render is the only way that mistake surfaces before a learner
124
+ * sits the paper. In `practice` mode it stays optional: a random per-mount
125
+ * seed is used, which is stable within the mount and deliberately not
126
+ * reproducible. That fallback is also not SSR-safe (server and client would
127
+ * invent different orders and hydration would mismatch), so supply a seed
128
+ * for any server-rendered sequence regardless of mode.
129
+ */
130
+ shuffleSeed?: string;
131
+ /** Renders author-supplied rich text; forwarded to the stimulus panel and every activity. */
132
+ sanitizeHtml?: HtmlSanitizer;
60
133
  theme?: Partial<ThemeTokens>;
61
134
  locale?: string;
62
135
  disabled?: boolean;
@@ -67,7 +140,12 @@ interface ActivitySequenceProps {
67
140
  * the learner may move back and forth; activities keep their own submit and
68
141
  * scoring. On navigation, focus moves to the question region and the position
69
142
  * is announced via an aria-live region.
143
+ *
144
+ * Item groups are flattened into consecutive questions; the group's stimulus
145
+ * is mounted ONCE, beside the question region rather than inside it, and shown
146
+ * alongside every question in the group — so a passage stays put, and a
147
+ * recording keeps its position, as the learner moves between its questions.
70
148
  */
71
- declare function ActivitySequence({ activities, renderers, onActivityComplete, onComplete, onFinished, onInteraction, renderMode, theme, locale, disabled, }: ActivitySequenceProps): React.JSX.Element;
149
+ declare function ActivitySequence({ activities, renderers, onActivityComplete, onComplete, onFinished, onSubmit, onInteraction, renderMode, shuffle, shuffleSeed, sanitizeHtml, theme, locale, disabled, }: ActivitySequenceProps): React.JSX.Element;
72
150
 
73
151
  export { type ActivityRenderer, ActivitySequence, type ActivitySequenceProps, type SequenceItemOutcome };
@@ -1,7 +1,7 @@
1
- import { ActivityData, ActivityResult, InteractionEvent, ThemeTokens } from '@intellectif/lk-core';
1
+ import { SequenceEntry, ActivityResult, LearnerResponse, InteractionEvent, ThemeTokens } from '@intellectif/lk-core';
2
2
  import { ComponentType } from 'react';
3
- import { A as ActivityProps, R as RenderMode } from '../types-CNmjqD6M.js';
4
- import { a as WrittenResponseSubmission } from '../WrittenResponse-BHhP936i.js';
3
+ import { A as ActivityProps, b as RenderableActivity, R as RenderMode, H as HtmlSanitizer } from '../types-CrURyd9-.js';
4
+ import { a as WrittenResponseSubmission } from '../WrittenResponse-Dkg7FUt-.js';
5
5
 
6
6
  /**
7
7
  * What one finished slot in a sequence produced. Two kinds, because two kinds
@@ -11,15 +11,30 @@ import { a as WrittenResponseSubmission } from '../WrittenResponse-BHhP936i.js';
11
11
  */
12
12
  type SequenceItemOutcome = {
13
13
  kind: 'scored';
14
+ /** Presented position. */
14
15
  index: number;
16
+ /** Slot identity from `flattenSequence` — stable under shuffling; the `slotId` to score with. */
17
+ slotId: string;
15
18
  activityId: string;
16
19
  result: ActivityResult;
17
20
  } | {
18
21
  kind: 'submitted';
19
22
  index: number;
23
+ slotId: string;
20
24
  activityId: string;
21
25
  /** Ungraded submission; the grade arrives asynchronously. */
22
26
  submission: WrittenResponseSubmission;
27
+ } | {
28
+ kind: 'responded';
29
+ index: number;
30
+ slotId: string;
31
+ activityId: string;
32
+ /**
33
+ * The raw answer, with no grade of any kind. This is what an `exam` slot
34
+ * produces: the client is forbidden to score, so a response is all there
35
+ * is until the server grades it.
36
+ */
37
+ response: LearnerResponse;
23
38
  };
24
39
  /**
25
40
  * A component that can render one activity inside a sequence. Register one per
@@ -28,23 +43,57 @@ type SequenceItemOutcome = {
28
43
  */
29
44
  type ActivityRenderer = ComponentType<ActivityProps>;
30
45
  interface ActivitySequenceProps {
31
- /** The ordered set of activities to present, one at a time. */
32
- activities: ActivityData[];
46
+ /**
47
+ * The ordered set of entries to present, one question at a time: loose
48
+ * activities, and item groups — a shared passage, recording or image with
49
+ * the questions that refer to it. A group's stimulus stays on screen
50
+ * alongside each of its questions.
51
+ *
52
+ * Accepts `redact()` projections. For data straight off a server, pass it
53
+ * through `asRenderableSequence()` — see that helper for why a cast is
54
+ * unavoidable there — and set `renderMode="exam"`.
55
+ */
56
+ activities: readonly SequenceEntry<RenderableActivity>[];
33
57
  /**
34
58
  * Renderers for activity types beyond the built-ins, keyed by `data.type`.
35
59
  * A key matching a built-in overrides it, so a consumer can replace the
36
60
  * bundled renderer without forking the sequencer.
37
61
  */
38
62
  renderers?: Readonly<Record<string, ActivityRenderer>>;
39
- /** Called whenever an individual activity is scored at submit time. */
40
- onActivityComplete?: (result: ActivityResult, index: number) => void;
63
+ /**
64
+ * Called whenever an individual activity is scored at submit time — the
65
+ * incremental persist hook.
66
+ *
67
+ * `slotId` is the identity to store the result against, NOT `index`.
68
+ * `index` is where the question was PRESENTED, which is not stable: it moves
69
+ * under shuffling, and it already differs from the slot identity whenever a
70
+ * group is present (the second entry of a sequence is presented at index 1
71
+ * but is slot `"1.0"` if it is a group's first question). `composeAssessmentScore`
72
+ * scores by `slotId`, so persisting `index` cannot be reconciled with it.
73
+ */
74
+ onActivityComplete?: (result: ActivityResult, index: number, slotId: string) => void;
75
+ /**
76
+ * Called on every submit with the learner's raw response and the identity of
77
+ * the slot that produced it — before any grading, in every render mode.
78
+ *
79
+ * **This is the only response channel an `exam` sequence has.** In `exam`
80
+ * mode the components never grade, so `onActivityComplete` cannot fire and
81
+ * `onComplete` never will; without this prop nothing a learner submitted
82
+ * would reach the consumer at all. Persist `response` against `slotId`.
83
+ */
84
+ onSubmit?: (response: LearnerResponse, slot: {
85
+ slotId: string;
86
+ index: number;
87
+ activityId: string;
88
+ }) => void;
41
89
  /**
42
90
  * Called once every activity has been completed, with the scored results.
43
91
  *
44
92
  * Fires only when EVERY item produced a score. A set containing a
45
93
  * deferred-graded activity (a written response) can never satisfy that, so
46
94
  * use `onFinished` for mixed sets — it is the general completion signal and
47
- * reports both kinds of outcome.
95
+ * reports both kinds of outcome. It also carries `slotId` per item, which
96
+ * this callback's bare array cannot.
48
97
  */
49
98
  onComplete?: (results: ActivityResult[]) => void;
50
99
  /**
@@ -57,6 +106,30 @@ interface ActivitySequenceProps {
57
106
  onInteraction?: (event: InteractionEvent) => void;
58
107
  /** Forwarded to each activity. `exam` and `review` disable local scoring. */
59
108
  renderMode?: RenderMode;
109
+ /**
110
+ * `entries` shuffles the top-level entries; a group moves as one block, and
111
+ * the order INSIDE a group follows the group's own `shuffle` setting.
112
+ * Default `none`: authored order.
113
+ */
114
+ shuffle?: 'none' | 'entries';
115
+ /**
116
+ * Seed for every shuffle in this sequence (`shuffle: 'entries'` and any
117
+ * group with `shuffle: 'within-group'`). Supply the attempt id, so the
118
+ * server's `flattenSequence(entries, { seed })` derives the same order this
119
+ * pager shows.
120
+ *
121
+ * **Required in `exam` and `review` mode** — omitting it throws. An order
122
+ * nobody can reproduce cannot be reconciled with a recorded attempt, and
123
+ * failing at render is the only way that mistake surfaces before a learner
124
+ * sits the paper. In `practice` mode it stays optional: a random per-mount
125
+ * seed is used, which is stable within the mount and deliberately not
126
+ * reproducible. That fallback is also not SSR-safe (server and client would
127
+ * invent different orders and hydration would mismatch), so supply a seed
128
+ * for any server-rendered sequence regardless of mode.
129
+ */
130
+ shuffleSeed?: string;
131
+ /** Renders author-supplied rich text; forwarded to the stimulus panel and every activity. */
132
+ sanitizeHtml?: HtmlSanitizer;
60
133
  theme?: Partial<ThemeTokens>;
61
134
  locale?: string;
62
135
  disabled?: boolean;
@@ -67,7 +140,12 @@ interface ActivitySequenceProps {
67
140
  * the learner may move back and forth; activities keep their own submit and
68
141
  * scoring. On navigation, focus moves to the question region and the position
69
142
  * is announced via an aria-live region.
143
+ *
144
+ * Item groups are flattened into consecutive questions; the group's stimulus
145
+ * is mounted ONCE, beside the question region rather than inside it, and shown
146
+ * alongside every question in the group — so a passage stays put, and a
147
+ * recording keeps its position, as the learner moves between its questions.
70
148
  */
71
- declare function ActivitySequence({ activities, renderers, onActivityComplete, onComplete, onFinished, onInteraction, renderMode, theme, locale, disabled, }: ActivitySequenceProps): React.JSX.Element;
149
+ declare function ActivitySequence({ activities, renderers, onActivityComplete, onComplete, onFinished, onSubmit, onInteraction, renderMode, shuffle, shuffleSeed, sanitizeHtml, theme, locale, disabled, }: ActivitySequenceProps): React.JSX.Element;
72
150
 
73
151
  export { type ActivityRenderer, ActivitySequence, type ActivitySequenceProps, type SequenceItemOutcome };
@@ -1,8 +1,10 @@
1
- export { ActivitySequence } from '../chunk-BGWXN44S.js';
2
- import '../chunk-ZVFWJTT4.js';
3
- import '../chunk-3X7MYAFT.js';
4
- import '../chunk-AEQQ7VPF.js';
5
- import '../chunk-UIGIYYGY.js';
1
+ export { ActivitySequence } from '../chunk-NBFTCGQ5.js';
2
+ import '../chunk-5SYL5CJ2.js';
3
+ import '../chunk-3DNJDP73.js';
4
+ import '../chunk-67WDTQMG.js';
5
+ import '../chunk-6F4X2NKL.js';
6
+ import '../chunk-UQ3BBEIT.js';
7
+ import '../chunk-GB5URWM4.js';
6
8
  import '../chunk-5HVUKXF3.js';
7
9
  //# sourceMappingURL=ActivitySequence.js.map
8
10
  //# sourceMappingURL=ActivitySequence.js.map
@@ -1,14 +1,15 @@
1
1
  'use strict';
2
2
 
3
- var chunkUXO6KYSZ_cjs = require('../chunk-UXO6KYSZ.cjs');
4
- require('../chunk-QHOV2A6M.cjs');
3
+ var chunk67RIIDZX_cjs = require('../chunk-67RIIDZX.cjs');
4
+ require('../chunk-PGEG7UZJ.cjs');
5
+ require('../chunk-4HZ7LQIH.cjs');
5
6
  require('../chunk-HD2AIQRD.cjs');
6
7
 
7
8
 
8
9
 
9
10
  Object.defineProperty(exports, "FillInTheBlanks", {
10
11
  enumerable: true,
11
- get: function () { return chunkUXO6KYSZ_cjs.FillInTheBlanks; }
12
+ get: function () { return chunk67RIIDZX_cjs.FillInTheBlanks; }
12
13
  });
13
14
  //# sourceMappingURL=FillInTheBlanks.cjs.map
14
15
  //# sourceMappingURL=FillInTheBlanks.cjs.map
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { FillInTheBlanksData } from '@intellectif/lk-core';
3
- import { A as ActivityProps } from '../types-CNmjqD6M.cjs';
3
+ import { A as ActivityProps } from '../types-CrURyd9-.cjs';
4
4
 
5
5
  interface FillInTheBlanksProps extends ActivityProps<FillInTheBlanksData> {
6
6
  /**
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { FillInTheBlanksData } from '@intellectif/lk-core';
3
- import { A as ActivityProps } from '../types-CNmjqD6M.js';
3
+ import { A as ActivityProps } from '../types-CrURyd9-.js';
4
4
 
5
5
  interface FillInTheBlanksProps extends ActivityProps<FillInTheBlanksData> {
6
6
  /**
@@ -1,5 +1,6 @@
1
- export { FillInTheBlanks } from '../chunk-3X7MYAFT.js';
2
- import '../chunk-UIGIYYGY.js';
1
+ export { FillInTheBlanks } from '../chunk-3DNJDP73.js';
2
+ import '../chunk-6F4X2NKL.js';
3
+ import '../chunk-GB5URWM4.js';
3
4
  import '../chunk-5HVUKXF3.js';
4
5
  //# sourceMappingURL=FillInTheBlanks.js.map
5
6
  //# sourceMappingURL=FillInTheBlanks.js.map
@@ -1,14 +1,15 @@
1
1
  'use strict';
2
2
 
3
- var chunkW6BH2YMZ_cjs = require('../chunk-W6BH2YMZ.cjs');
4
- require('../chunk-QHOV2A6M.cjs');
3
+ var chunkWCVD5LVG_cjs = require('../chunk-WCVD5LVG.cjs');
4
+ require('../chunk-PGEG7UZJ.cjs');
5
+ require('../chunk-4HZ7LQIH.cjs');
5
6
  require('../chunk-HD2AIQRD.cjs');
6
7
 
7
8
 
8
9
 
9
10
  Object.defineProperty(exports, "MultipleChoice", {
10
11
  enumerable: true,
11
- get: function () { return chunkW6BH2YMZ_cjs.MultipleChoice; }
12
+ get: function () { return chunkWCVD5LVG_cjs.MultipleChoice; }
12
13
  });
13
14
  //# sourceMappingURL=MultipleChoice.cjs.map
14
15
  //# sourceMappingURL=MultipleChoice.cjs.map
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { MultipleChoiceData } from '@intellectif/lk-core';
3
- import { A as ActivityProps } from '../types-CNmjqD6M.cjs';
3
+ import { A as ActivityProps } from '../types-CrURyd9-.cjs';
4
4
 
5
5
  interface MultipleChoiceProps extends ActivityProps<MultipleChoiceData> {
6
6
  /**
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { MultipleChoiceData } from '@intellectif/lk-core';
3
- import { A as ActivityProps } from '../types-CNmjqD6M.js';
3
+ import { A as ActivityProps } from '../types-CrURyd9-.js';
4
4
 
5
5
  interface MultipleChoiceProps extends ActivityProps<MultipleChoiceData> {
6
6
  /**
@@ -1,5 +1,6 @@
1
- export { MultipleChoice } from '../chunk-ZVFWJTT4.js';
2
- import '../chunk-UIGIYYGY.js';
1
+ export { MultipleChoice } from '../chunk-5SYL5CJ2.js';
2
+ import '../chunk-6F4X2NKL.js';
3
+ import '../chunk-GB5URWM4.js';
3
4
  import '../chunk-5HVUKXF3.js';
4
5
  //# sourceMappingURL=MultipleChoice.js.map
5
6
  //# sourceMappingURL=MultipleChoice.js.map
@@ -0,0 +1,13 @@
1
+ 'use strict';
2
+
3
+ var chunkNEWGUDA5_cjs = require('../chunk-NEWGUDA5.cjs');
4
+ require('../chunk-4HZ7LQIH.cjs');
5
+
6
+
7
+
8
+ Object.defineProperty(exports, "StimulusPanel", {
9
+ enumerable: true,
10
+ get: function () { return chunkNEWGUDA5_cjs.StimulusPanel; }
11
+ });
12
+ //# sourceMappingURL=StimulusPanel.cjs.map
13
+ //# sourceMappingURL=StimulusPanel.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"StimulusPanel.cjs"}
@@ -0,0 +1,30 @@
1
+ import { Stimulus } from '@intellectif/lk-core';
2
+ import { H as HtmlSanitizer } from '../types-CrURyd9-.cjs';
3
+
4
+ interface StimulusPanelProps {
5
+ stimulus: Stimulus;
6
+ /**
7
+ * 1-based presented positions of the first and last question this material
8
+ * serves, rendered as "Questions 3–8" so a learner knows how far the
9
+ * passage carries.
10
+ */
11
+ range?: {
12
+ first: number;
13
+ last: number;
14
+ };
15
+ /** Renders `stimulus.bodyHtml` when provided. See `HtmlSanitizer`. */
16
+ sanitizeHtml?: HtmlSanitizer;
17
+ locale?: string;
18
+ }
19
+ /**
20
+ * Presents a shared stimulus — the passage, recording or image an item group's
21
+ * questions refer to. A landmark region named by its title (or by its kind),
22
+ * so a screen-reader user can jump back to the material from any question.
23
+ *
24
+ * Rich text follows the SDK-wide rule: `bodyHtml` is rendered only through a
25
+ * caller-supplied sanitiser, and the plain `body` is the fallback — which the
26
+ * schema guarantees exists whenever `bodyHtml` does.
27
+ */
28
+ declare function StimulusPanel({ stimulus, range, sanitizeHtml, locale, }: StimulusPanelProps): React.JSX.Element;
29
+
30
+ export { StimulusPanel, type StimulusPanelProps };
@@ -0,0 +1,30 @@
1
+ import { Stimulus } from '@intellectif/lk-core';
2
+ import { H as HtmlSanitizer } from '../types-CrURyd9-.js';
3
+
4
+ interface StimulusPanelProps {
5
+ stimulus: Stimulus;
6
+ /**
7
+ * 1-based presented positions of the first and last question this material
8
+ * serves, rendered as "Questions 3–8" so a learner knows how far the
9
+ * passage carries.
10
+ */
11
+ range?: {
12
+ first: number;
13
+ last: number;
14
+ };
15
+ /** Renders `stimulus.bodyHtml` when provided. See `HtmlSanitizer`. */
16
+ sanitizeHtml?: HtmlSanitizer;
17
+ locale?: string;
18
+ }
19
+ /**
20
+ * Presents a shared stimulus — the passage, recording or image an item group's
21
+ * questions refer to. A landmark region named by its title (or by its kind),
22
+ * so a screen-reader user can jump back to the material from any question.
23
+ *
24
+ * Rich text follows the SDK-wide rule: `bodyHtml` is rendered only through a
25
+ * caller-supplied sanitiser, and the plain `body` is the fallback — which the
26
+ * schema guarantees exists whenever `bodyHtml` does.
27
+ */
28
+ declare function StimulusPanel({ stimulus, range, sanitizeHtml, locale, }: StimulusPanelProps): React.JSX.Element;
29
+
30
+ export { StimulusPanel, type StimulusPanelProps };
@@ -0,0 +1,4 @@
1
+ export { StimulusPanel } from '../chunk-UQ3BBEIT.js';
2
+ import '../chunk-GB5URWM4.js';
3
+ //# sourceMappingURL=StimulusPanel.js.map
4
+ //# sourceMappingURL=StimulusPanel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"StimulusPanel.js"}
@@ -1,14 +1,15 @@
1
1
  'use strict';
2
2
 
3
- var chunk7MW7HGOA_cjs = require('../chunk-7MW7HGOA.cjs');
4
- require('../chunk-QHOV2A6M.cjs');
3
+ var chunk6COTYW77_cjs = require('../chunk-6COTYW77.cjs');
4
+ require('../chunk-PGEG7UZJ.cjs');
5
+ require('../chunk-4HZ7LQIH.cjs');
5
6
  require('../chunk-HD2AIQRD.cjs');
6
7
 
7
8
 
8
9
 
9
10
  Object.defineProperty(exports, "WrittenResponse", {
10
11
  enumerable: true,
11
- get: function () { return chunk7MW7HGOA_cjs.WrittenResponse; }
12
+ get: function () { return chunk6COTYW77_cjs.WrittenResponse; }
12
13
  });
13
14
  //# sourceMappingURL=WrittenResponse.cjs.map
14
15
  //# sourceMappingURL=WrittenResponse.cjs.map
@@ -1,7 +1,7 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { W as WrittenResponseProps } from '../WrittenResponse-B50EjVR0.cjs';
3
- export { a as WrittenResponseSubmission } from '../WrittenResponse-B50EjVR0.cjs';
4
- export { H as HtmlSanitizer, R as RenderMode, a as Renderable } from '../types-CNmjqD6M.cjs';
2
+ import { W as WrittenResponseProps } from '../WrittenResponse-DqQ0NjPK.cjs';
3
+ export { a as WrittenResponseSubmission } from '../WrittenResponse-DqQ0NjPK.cjs';
4
+ export { H as HtmlSanitizer, R as RenderMode, a as Renderable } from '../types-CrURyd9-.cjs';
5
5
  import '@intellectif/lk-core';
6
6
 
7
7
  /**
@@ -1,7 +1,7 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { W as WrittenResponseProps } from '../WrittenResponse-BHhP936i.js';
3
- export { a as WrittenResponseSubmission } from '../WrittenResponse-BHhP936i.js';
4
- export { H as HtmlSanitizer, R as RenderMode, a as Renderable } from '../types-CNmjqD6M.js';
2
+ import { W as WrittenResponseProps } from '../WrittenResponse-Dkg7FUt-.js';
3
+ export { a as WrittenResponseSubmission } from '../WrittenResponse-Dkg7FUt-.js';
4
+ export { H as HtmlSanitizer, R as RenderMode, a as Renderable } from '../types-CrURyd9-.js';
5
5
  import '@intellectif/lk-core';
6
6
 
7
7
  /**