@intellectif/lk-react 1.0.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +112 -0
- package/dist/{chunk-5KW7TFX3.js → chunk-32WWQOG3.js} +13 -5
- package/dist/chunk-32WWQOG3.js.map +1 -0
- package/dist/{chunk-O3GWWJFS.cjs → chunk-73XCWYKD.cjs} +18 -10
- package/dist/chunk-73XCWYKD.cjs.map +1 -0
- package/dist/{chunk-IZNMQSQP.js → chunk-E4MNA2IQ.js} +17 -3
- package/dist/chunk-E4MNA2IQ.js.map +1 -0
- package/dist/{chunk-W2L66WHW.js → chunk-G5ZEWJRA.js} +28 -12
- package/dist/chunk-G5ZEWJRA.js.map +1 -0
- package/dist/{chunk-TVK3SVV6.cjs → chunk-IYLQSNLE.cjs} +17 -3
- package/dist/chunk-IYLQSNLE.cjs.map +1 -0
- package/dist/chunk-KJNQLAB5.cjs +158 -0
- package/dist/chunk-KJNQLAB5.cjs.map +1 -0
- package/dist/{chunk-QBA6UXMS.cjs → chunk-MKH5THDR.cjs} +32 -16
- package/dist/chunk-MKH5THDR.cjs.map +1 -0
- package/dist/{chunk-ZPD7BGCF.js → chunk-OS7MO2OW.js} +18 -5
- package/dist/chunk-OS7MO2OW.js.map +1 -0
- package/dist/{chunk-6OBRYL4C.cjs → chunk-QHOV2A6M.cjs} +11 -2
- package/dist/chunk-QHOV2A6M.cjs.map +1 -0
- package/dist/{chunk-RI53A36N.cjs → chunk-SH7BRP4M.cjs} +18 -5
- package/dist/chunk-SH7BRP4M.cjs.map +1 -0
- package/dist/{chunk-L3EV5LIX.js → chunk-UIGIYYGY.js} +11 -3
- package/dist/chunk-UIGIYYGY.js.map +1 -0
- package/dist/chunk-V5EN3ESV.js +156 -0
- package/dist/chunk-V5EN3ESV.js.map +1 -0
- package/dist/components/ActivitySequence.cjs +5 -5
- package/dist/components/ActivitySequence.js +4 -4
- package/dist/components/FillInTheBlanks.cjs +3 -3
- package/dist/components/FillInTheBlanks.js +2 -2
- package/dist/components/MultipleChoice.cjs +3 -3
- package/dist/components/MultipleChoice.js +2 -2
- package/dist/components/WrittenResponse.cjs +14 -0
- package/dist/components/WrittenResponse.cjs.map +1 -0
- package/dist/components/WrittenResponse.d.cts +48 -0
- package/dist/components/WrittenResponse.d.ts +48 -0
- package/dist/components/WrittenResponse.js +5 -0
- package/dist/components/WrittenResponse.js.map +1 -0
- package/dist/hooks/useXAPI.cjs +2 -2
- package/dist/hooks/useXAPI.js +1 -1
- package/dist/index.cjs +14 -9
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +6 -5
- package/dist/theme/skin.css +85 -0
- package/package.json +18 -4
- package/dist/chunk-5KW7TFX3.js.map +0 -1
- package/dist/chunk-6OBRYL4C.cjs.map +0 -1
- package/dist/chunk-IZNMQSQP.js.map +0 -1
- package/dist/chunk-L3EV5LIX.js.map +0 -1
- package/dist/chunk-O3GWWJFS.cjs.map +0 -1
- package/dist/chunk-QBA6UXMS.cjs.map +0 -1
- package/dist/chunk-RI53A36N.cjs.map +0 -1
- package/dist/chunk-TVK3SVV6.cjs.map +0 -1
- package/dist/chunk-W2L66WHW.js.map +0 -1
- package/dist/chunk-ZPD7BGCF.js.map +0 -1
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { ActivityErrorBoundary, isDevelopment, ActivityMedia, FeedbackRegion, ANONYMOUS_ACTOR, objectIdFor } from './chunk-UIGIYYGY.js';
|
|
2
|
+
import { useActivityState } from './chunk-5HVUKXF3.js';
|
|
3
|
+
import { validateActivity, ActivitySchemaError, countWords, evaluate, xAPIBuilder } from '@intellectif/lk-core';
|
|
4
|
+
import { useMemo, useState, useEffect } from 'react';
|
|
5
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
function WrittenResponse({
|
|
8
|
+
data,
|
|
9
|
+
onSubmitted,
|
|
10
|
+
onInteraction,
|
|
11
|
+
theme,
|
|
12
|
+
locale,
|
|
13
|
+
disabled
|
|
14
|
+
}) {
|
|
15
|
+
const devError = useMemo(() => {
|
|
16
|
+
if (!isDevelopment()) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
const result = validateActivity("written-response", data);
|
|
20
|
+
return result.success ? null : new ActivitySchemaError("written-response", result.errors);
|
|
21
|
+
}, [data]);
|
|
22
|
+
const { state, start, complete, getTimeSpent, reset } = useActivityState();
|
|
23
|
+
const [text, setText] = useState("");
|
|
24
|
+
const [summary, setSummary] = useState(null);
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
setText("");
|
|
27
|
+
setSummary(null);
|
|
28
|
+
reset();
|
|
29
|
+
}, [data, reset]);
|
|
30
|
+
if (devError) {
|
|
31
|
+
throw devError;
|
|
32
|
+
}
|
|
33
|
+
const submitted = state === "completed";
|
|
34
|
+
const inactive = disabled === true || submitted;
|
|
35
|
+
const wordCount = countWords(text);
|
|
36
|
+
const withinBounds = wordCount >= data.minWords && wordCount <= data.maxWords;
|
|
37
|
+
const handleChange = (value) => {
|
|
38
|
+
if (inactive) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (state === "idle") {
|
|
42
|
+
start();
|
|
43
|
+
}
|
|
44
|
+
setText(value);
|
|
45
|
+
onInteraction?.({
|
|
46
|
+
type: "text-changed",
|
|
47
|
+
activityId: data.id,
|
|
48
|
+
timestamp: Date.now(),
|
|
49
|
+
payload: { wordCount: countWords(value) }
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
const handleSubmit = (event) => {
|
|
53
|
+
event.preventDefault();
|
|
54
|
+
if (inactive || text.trim().length === 0) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const outcome = evaluate(data, { type: "written-response", text, wordCount });
|
|
58
|
+
complete();
|
|
59
|
+
const timeSpent = getTimeSpent();
|
|
60
|
+
const partial = outcome.status === "deferred" ? outcome.partial : void 0;
|
|
61
|
+
const finalWordCount = typeof partial?.wordCount === "number" ? partial.wordCount : wordCount;
|
|
62
|
+
const finalWithinBounds = typeof partial?.withinWordBounds === "boolean" ? partial.withinWordBounds : withinBounds;
|
|
63
|
+
const xapiStatement = xAPIBuilder.buildSubmittedStatement({
|
|
64
|
+
actor: ANONYMOUS_ACTOR,
|
|
65
|
+
object: {
|
|
66
|
+
id: objectIdFor(data.id),
|
|
67
|
+
name: { [data.locale ?? "en-US"]: data.title },
|
|
68
|
+
type: "http://adlnet.gov/expapi/activities/cmi.interaction",
|
|
69
|
+
interactionType: "long-fill-in"
|
|
70
|
+
},
|
|
71
|
+
timeSpentMs: timeSpent,
|
|
72
|
+
response: text,
|
|
73
|
+
resultExtensions: {
|
|
74
|
+
"urn:learning-kit:extension:word-count": finalWordCount,
|
|
75
|
+
"urn:learning-kit:extension:within-word-bounds": finalWithinBounds
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
onSubmitted({
|
|
79
|
+
text,
|
|
80
|
+
wordCount: finalWordCount,
|
|
81
|
+
withinWordBounds: finalWithinBounds,
|
|
82
|
+
timeSpent,
|
|
83
|
+
xapiStatement
|
|
84
|
+
});
|
|
85
|
+
setSummary("Response submitted. It will be graded and your result will appear here later.");
|
|
86
|
+
onInteraction?.({
|
|
87
|
+
type: "submitted",
|
|
88
|
+
activityId: data.id,
|
|
89
|
+
timestamp: Date.now(),
|
|
90
|
+
payload: { wordCount: finalWordCount, withinWordBounds: finalWithinBounds }
|
|
91
|
+
});
|
|
92
|
+
};
|
|
93
|
+
const promptId = `${data.id}-prompt`;
|
|
94
|
+
const counterId = `${data.id}-counter`;
|
|
95
|
+
const boundsLabel = data.minWords > 0 ? `${data.minWords}\u2013${data.maxWords} words` : `up to ${data.maxWords} words`;
|
|
96
|
+
return /* @__PURE__ */ jsxs(
|
|
97
|
+
"form",
|
|
98
|
+
{
|
|
99
|
+
className: "lk-wr",
|
|
100
|
+
"aria-label": data.title,
|
|
101
|
+
lang: locale,
|
|
102
|
+
style: theme,
|
|
103
|
+
onSubmit: handleSubmit,
|
|
104
|
+
children: [
|
|
105
|
+
data.media ? /* @__PURE__ */ jsx(ActivityMedia, { media: data.media }) : null,
|
|
106
|
+
/* @__PURE__ */ jsx("p", { className: "lk-wr-prompt", id: promptId, children: data.prompt }),
|
|
107
|
+
/* @__PURE__ */ jsx(
|
|
108
|
+
"textarea",
|
|
109
|
+
{
|
|
110
|
+
className: "lk-wr-textarea",
|
|
111
|
+
"aria-labelledby": promptId,
|
|
112
|
+
"aria-describedby": counterId,
|
|
113
|
+
value: text,
|
|
114
|
+
onChange: (event) => handleChange(event.target.value),
|
|
115
|
+
disabled: inactive,
|
|
116
|
+
rows: 8
|
|
117
|
+
}
|
|
118
|
+
),
|
|
119
|
+
/* @__PURE__ */ jsxs(
|
|
120
|
+
"div",
|
|
121
|
+
{
|
|
122
|
+
className: "lk-wr-counter",
|
|
123
|
+
id: counterId,
|
|
124
|
+
"aria-live": "polite",
|
|
125
|
+
"data-within-bounds": withinBounds,
|
|
126
|
+
children: [
|
|
127
|
+
wordCount,
|
|
128
|
+
" ",
|
|
129
|
+
wordCount === 1 ? "word" : "words",
|
|
130
|
+
" (",
|
|
131
|
+
boundsLabel,
|
|
132
|
+
")"
|
|
133
|
+
]
|
|
134
|
+
}
|
|
135
|
+
),
|
|
136
|
+
/* @__PURE__ */ jsx(
|
|
137
|
+
"button",
|
|
138
|
+
{
|
|
139
|
+
type: "submit",
|
|
140
|
+
className: "lk-wr-submit",
|
|
141
|
+
disabled: inactive || text.trim().length === 0,
|
|
142
|
+
children: "Submit"
|
|
143
|
+
}
|
|
144
|
+
),
|
|
145
|
+
/* @__PURE__ */ jsx(FeedbackRegion, { id: `${data.id}-feedback`, children: summary })
|
|
146
|
+
]
|
|
147
|
+
}
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
function WrittenResponse2(props) {
|
|
151
|
+
return /* @__PURE__ */ jsx(ActivityErrorBoundary, { activityTitle: props.data?.title, children: /* @__PURE__ */ jsx(WrittenResponse, { ...props }) });
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export { WrittenResponse2 as WrittenResponse };
|
|
155
|
+
//# sourceMappingURL=chunk-V5EN3ESV.js.map
|
|
156
|
+
//# sourceMappingURL=chunk-V5EN3ESV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/WrittenResponse/WrittenResponse.tsx","../src/components/WrittenResponse/index.tsx"],"names":["WrittenResponse","jsx"],"mappings":";;;;;;AAwDO,SAAS,eAAA,CAAgB;AAAA,EAC9B,IAAA;AAAA,EACA,WAAA;AAAA,EACA,aAAA;AAAA,EACA,KAAA;AAAA,EACA,MAAA;AAAA,EACA;AACF,CAAA,EAAyB;AAEvB,EAAA,MAAM,QAAA,GAAW,QAAQ,MAAM;AAC7B,IAAA,IAAI,CAAC,eAAc,EAAG;AACpB,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,MAAM,MAAA,GAAS,gBAAA,CAAiB,kBAAA,EAAoB,IAAI,CAAA;AACxD,IAAA,OAAO,OAAO,OAAA,GAAU,IAAA,GAAO,IAAI,mBAAA,CAAoB,kBAAA,EAAoB,OAAO,MAAM,CAAA;AAAA,EAC1F,CAAA,EAAG,CAAC,IAAI,CAAC,CAAA;AAET,EAAA,MAAM,EAAE,KAAA,EAAO,KAAA,EAAO,UAAU,YAAA,EAAc,KAAA,KAAU,gBAAA,EAAiB;AACzE,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,SAAS,EAAE,CAAA;AACnC,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAwB,IAAI,CAAA;AAI1D,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,OAAA,CAAQ,EAAE,CAAA;AACV,IAAA,UAAA,CAAW,IAAI,CAAA;AACf,IAAA,KAAA,EAAM;AAAA,EACR,CAAA,EAAG,CAAC,IAAA,EAAM,KAAK,CAAC,CAAA;AAEhB,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,MAAM,QAAA;AAAA,EACR;AAEA,EAAA,MAAM,YAAY,KAAA,KAAU,WAAA;AAC5B,EAAA,MAAM,QAAA,GAAW,aAAa,IAAA,IAAQ,SAAA;AACtC,EAAA,MAAM,SAAA,GAAY,WAAW,IAAI,CAAA;AACjC,EAAA,MAAM,YAAA,GAAe,SAAA,IAAa,IAAA,CAAK,QAAA,IAAY,aAAa,IAAA,CAAK,QAAA;AAErE,EAAA,MAAM,YAAA,GAAe,CAAC,KAAA,KAAwB;AAC5C,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA;AAAA,IACF;AACA,IAAA,IAAI,UAAU,MAAA,EAAQ;AACpB,MAAA,KAAA,EAAM;AAAA,IACR;AACA,IAAA,OAAA,CAAQ,KAAK,CAAA;AACb,IAAA,aAAA,GAAgB;AAAA,MACd,IAAA,EAAM,cAAA;AAAA,MACN,YAAY,IAAA,CAAK,EAAA;AAAA,MACjB,SAAA,EAAW,KAAK,GAAA,EAAI;AAAA,MACpB,OAAA,EAAS,EAAE,SAAA,EAAW,UAAA,CAAW,KAAK,CAAA;AAAE,KACzC,CAAA;AAAA,EACH,CAAA;AAEA,EAAA,MAAM,YAAA,GAAe,CAAC,KAAA,KAAiC;AACrD,IAAA,KAAA,CAAM,cAAA,EAAe;AACrB,IAAA,IAAI,QAAA,IAAY,IAAA,CAAK,IAAA,EAAK,CAAE,WAAW,CAAA,EAAG;AACxC,MAAA;AAAA,IACF;AACA,IAAA,MAAM,OAAA,GAAU,SAAS,IAAA,EAAM,EAAE,MAAM,kBAAA,EAAoB,IAAA,EAAM,WAAW,CAAA;AAC5E,IAAA,QAAA,EAAS;AACT,IAAA,MAAM,YAAY,YAAA,EAAa;AAC/B,IAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,MAAA,KAAW,UAAA,GAAa,QAAQ,OAAA,GAAU,MAAA;AAClE,IAAA,MAAM,iBAAiB,OAAO,OAAA,EAAS,SAAA,KAAc,QAAA,GAAW,QAAQ,SAAA,GAAY,SAAA;AACpF,IAAA,MAAM,oBACJ,OAAO,OAAA,EAAS,gBAAA,KAAqB,SAAA,GAAY,QAAQ,gBAAA,GAAmB,YAAA;AAC9E,IAAA,MAAM,aAAA,GAAgB,YAAY,uBAAA,CAAwB;AAAA,MACxD,KAAA,EAAO,eAAA;AAAA,MACP,MAAA,EAAQ;AAAA,QACN,EAAA,EAAI,WAAA,CAAY,IAAA,CAAK,EAAE,CAAA;AAAA,QACvB,IAAA,EAAM,EAAE,CAAC,IAAA,CAAK,UAAU,OAAO,GAAG,KAAK,KAAA,EAAM;AAAA,QAC7C,IAAA,EAAM,qDAAA;AAAA,QACN,eAAA,EAAiB;AAAA,OACnB;AAAA,MACA,WAAA,EAAa,SAAA;AAAA,MACb,QAAA,EAAU,IAAA;AAAA,MACV,gBAAA,EAAkB;AAAA,QAChB,uCAAA,EAAyC,cAAA;AAAA,QACzC,+CAAA,EAAiD;AAAA;AACnD,KACD,CAAA;AACD,IAAA,WAAA,CAAY;AAAA,MACV,IAAA;AAAA,MACA,SAAA,EAAW,cAAA;AAAA,MACX,gBAAA,EAAkB,iBAAA;AAAA,MAClB,SAAA;AAAA,MACA;AAAA,KACD,CAAA;AACD,IAAA,UAAA,CAAW,+EAA+E,CAAA;AAC1F,IAAA,aAAA,GAAgB;AAAA,MACd,IAAA,EAAM,WAAA;AAAA,MACN,YAAY,IAAA,CAAK,EAAA;AAAA,MACjB,SAAA,EAAW,KAAK,GAAA,EAAI;AAAA,MACpB,OAAA,EAAS,EAAE,SAAA,EAAW,cAAA,EAAgB,kBAAkB,iBAAA;AAAkB,KAC3E,CAAA;AAAA,EACH,CAAA;AAEA,EAAA,MAAM,QAAA,GAAW,CAAA,EAAG,IAAA,CAAK,EAAE,CAAA,OAAA,CAAA;AAC3B,EAAA,MAAM,SAAA,GAAY,CAAA,EAAG,IAAA,CAAK,EAAE,CAAA,QAAA,CAAA;AAC5B,EAAA,MAAM,WAAA,GACJ,IAAA,CAAK,QAAA,GAAW,CAAA,GAAI,CAAA,EAAG,IAAA,CAAK,QAAQ,CAAA,MAAA,EAAI,IAAA,CAAK,QAAQ,CAAA,MAAA,CAAA,GAAW,CAAA,MAAA,EAAS,KAAK,QAAQ,CAAA,MAAA,CAAA;AAExF,EAAA,uBACE,IAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAU,OAAA;AAAA,MACV,cAAY,IAAA,CAAK,KAAA;AAAA,MACjB,IAAA,EAAM,MAAA;AAAA,MACN,KAAA,EAAO,KAAA;AAAA,MACP,QAAA,EAAU,YAAA;AAAA,MAET,QAAA,EAAA;AAAA,QAAA,IAAA,CAAK,wBAAQ,GAAA,CAAC,aAAA,EAAA,EAAc,KAAA,EAAO,IAAA,CAAK,OAAO,CAAA,GAAK,IAAA;AAAA,4BACpD,GAAA,EAAA,EAAE,SAAA,EAAU,gBAAe,EAAA,EAAI,QAAA,EAC7B,eAAK,MAAA,EACR,CAAA;AAAA,wBACA,GAAA;AAAA,UAAC,UAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAU,gBAAA;AAAA,YACV,iBAAA,EAAiB,QAAA;AAAA,YACjB,kBAAA,EAAkB,SAAA;AAAA,YAClB,KAAA,EAAO,IAAA;AAAA,YACP,UAAU,CAAC,KAAA,KAAU,YAAA,CAAa,KAAA,CAAM,OAAO,KAAK,CAAA;AAAA,YACpD,QAAA,EAAU,QAAA;AAAA,YACV,IAAA,EAAM;AAAA;AAAA,SACR;AAAA,wBACA,IAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAU,eAAA;AAAA,YACV,EAAA,EAAI,SAAA;AAAA,YACJ,WAAA,EAAU,QAAA;AAAA,YACV,oBAAA,EAAoB,YAAA;AAAA,YAEnB,QAAA,EAAA;AAAA,cAAA,SAAA;AAAA,cAAU,GAAA;AAAA,cAAE,SAAA,KAAc,IAAI,MAAA,GAAS,OAAA;AAAA,cAAQ,IAAA;AAAA,cAAG,WAAA;AAAA,cAAY;AAAA;AAAA;AAAA,SACjE;AAAA,wBACA,GAAA;AAAA,UAAC,QAAA;AAAA,UAAA;AAAA,YACC,IAAA,EAAK,QAAA;AAAA,YACL,SAAA,EAAU,cAAA;AAAA,YACV,QAAA,EAAU,QAAA,IAAY,IAAA,CAAK,IAAA,GAAO,MAAA,KAAW,CAAA;AAAA,YAC9C,QAAA,EAAA;AAAA;AAAA,SAED;AAAA,4BACC,cAAA,EAAA,EAAe,EAAA,EAAI,GAAG,IAAA,CAAK,EAAE,aAAc,QAAA,EAAA,OAAA,EAAQ;AAAA;AAAA;AAAA,GACtD;AAEJ;ACrLO,SAASA,iBAAgB,KAAA,EAA6B;AAC3D,EAAA,uBACEC,GAAAA,CAAC,qBAAA,EAAA,EAAsB,aAAA,EAAe,KAAA,CAAM,IAAA,EAAM,KAAA,EAChD,QAAA,kBAAAA,GAAAA,CAAC,eAAA,EAAA,EAAqB,GAAG,KAAA,EAAO,CAAA,EAClC,CAAA;AAEJ","file":"chunk-V5EN3ESV.js","sourcesContent":["'use client';\n\nimport {\n ActivitySchemaError,\n countWords,\n evaluate,\n type InteractionEvent,\n type ThemeTokens,\n validateActivity,\n type WrittenResponseData,\n type XAPIStatement,\n xAPIBuilder,\n} from '@intellectif/lk-core';\nimport { type CSSProperties, useEffect, useMemo, useState } from 'react';\nimport { useActivityState } from '../../hooks/useActivityState.js';\nimport { ANONYMOUS_ACTOR, isDevelopment, objectIdFor } from '../_internal.js';\nimport { ActivityMedia } from '../shared/ActivityMedia.js';\nimport { FeedbackRegion } from '../shared/FeedbackRegion.js';\n\n/**\n * Payload delivered when the learner submits a written response. Grading is\n * DEFERRED (asynchronous AI/human grading), so there is no score here — and\n * deliberately no fake one: an ungraded submission must never be shown or\n * stored as a 0. The consumer persists `text` and grades it out-of-band.\n */\nexport interface WrittenResponseSubmission {\n /** The submitted text, verbatim. */\n text: string;\n /** Word count of `text`, recomputed with the canonical `countWords()`. */\n wordCount: number;\n /** Whether `wordCount` falls within the activity's `[minWords, maxWords]`. */\n withinWordBounds: boolean;\n /** Time in milliseconds from first interaction to submission. */\n timeSpent: number;\n /** The SUBMITTED-verb xAPI statement built for this submission (no score fields). */\n xapiStatement: XAPIStatement;\n}\n\n/**\n * Props for {@link WrittenResponse}. Mirrors `ActivityProps` except for the\n * completion callback: a deferred-grading activity completes with a\n * {@link WrittenResponseSubmission} (`onSubmitted`), not a scored\n * `ActivityResult` (`onComplete`) — deviation from Req 22.8 recorded in the\n * roadmap (§3.1): fabricating a score of 0 for ungraded work is the exact\n * bug this type exists to fix.\n */\nexport interface WrittenResponseProps {\n data: WrittenResponseData;\n onSubmitted: (submission: WrittenResponseSubmission) => void;\n onInteraction?: (event: InteractionEvent) => void;\n /** Per-instance token overrides, applied as inline CSS vars on the root. */\n theme?: Partial<ThemeTokens>;\n locale?: string;\n disabled?: boolean;\n}\n\nexport function WrittenResponse({\n data,\n onSubmitted,\n onInteraction,\n theme,\n locale,\n disabled,\n}: WrittenResponseProps) {\n // Dev-only boundary validation (Req 2.3), same convention as MC/FIB.\n const devError = useMemo(() => {\n if (!isDevelopment()) {\n return null;\n }\n const result = validateActivity('written-response', data);\n return result.success ? null : new ActivitySchemaError('written-response', result.errors);\n }, [data]);\n\n const { state, start, complete, getTimeSpent, reset } = useActivityState();\n const [text, setText] = useState('');\n const [summary, setSummary] = useState<string | null>(null);\n\n // Reset on data-prop change (Req 3.7).\n // biome-ignore lint/correctness/useExhaustiveDependencies: data is the reset trigger (Req 3.7)\n useEffect(() => {\n setText('');\n setSummary(null);\n reset();\n }, [data, reset]);\n\n if (devError) {\n throw devError;\n }\n\n const submitted = state === 'completed';\n const inactive = disabled === true || submitted;\n const wordCount = countWords(text);\n const withinBounds = wordCount >= data.minWords && wordCount <= data.maxWords;\n\n const handleChange = (value: string): void => {\n if (inactive) {\n return;\n }\n if (state === 'idle') {\n start();\n }\n setText(value);\n onInteraction?.({\n type: 'text-changed',\n activityId: data.id,\n timestamp: Date.now(),\n payload: { wordCount: countWords(value) },\n });\n };\n\n const handleSubmit = (event: React.FormEvent): void => {\n event.preventDefault();\n if (inactive || text.trim().length === 0) {\n return;\n }\n const outcome = evaluate(data, { type: 'written-response', text, wordCount });\n complete();\n const timeSpent = getTimeSpent();\n const partial = outcome.status === 'deferred' ? outcome.partial : undefined;\n const finalWordCount = typeof partial?.wordCount === 'number' ? partial.wordCount : wordCount;\n const finalWithinBounds =\n typeof partial?.withinWordBounds === 'boolean' ? partial.withinWordBounds : withinBounds;\n const xapiStatement = xAPIBuilder.buildSubmittedStatement({\n actor: ANONYMOUS_ACTOR,\n object: {\n id: objectIdFor(data.id),\n name: { [data.locale ?? 'en-US']: data.title },\n type: 'http://adlnet.gov/expapi/activities/cmi.interaction',\n interactionType: 'long-fill-in',\n },\n timeSpentMs: timeSpent,\n response: text,\n resultExtensions: {\n 'urn:learning-kit:extension:word-count': finalWordCount,\n 'urn:learning-kit:extension:within-word-bounds': finalWithinBounds,\n },\n });\n onSubmitted({\n text,\n wordCount: finalWordCount,\n withinWordBounds: finalWithinBounds,\n timeSpent,\n xapiStatement,\n });\n setSummary('Response submitted. It will be graded and your result will appear here later.');\n onInteraction?.({\n type: 'submitted',\n activityId: data.id,\n timestamp: Date.now(),\n payload: { wordCount: finalWordCount, withinWordBounds: finalWithinBounds },\n });\n };\n\n const promptId = `${data.id}-prompt`;\n const counterId = `${data.id}-counter`;\n const boundsLabel =\n data.minWords > 0 ? `${data.minWords}–${data.maxWords} words` : `up to ${data.maxWords} words`;\n\n return (\n <form\n className=\"lk-wr\"\n aria-label={data.title}\n lang={locale}\n style={theme as CSSProperties | undefined}\n onSubmit={handleSubmit}\n >\n {data.media ? <ActivityMedia media={data.media} /> : null}\n <p className=\"lk-wr-prompt\" id={promptId}>\n {data.prompt}\n </p>\n <textarea\n className=\"lk-wr-textarea\"\n aria-labelledby={promptId}\n aria-describedby={counterId}\n value={text}\n onChange={(event) => handleChange(event.target.value)}\n disabled={inactive}\n rows={8}\n />\n <div\n className=\"lk-wr-counter\"\n id={counterId}\n aria-live=\"polite\"\n data-within-bounds={withinBounds}\n >\n {wordCount} {wordCount === 1 ? 'word' : 'words'} ({boundsLabel})\n </div>\n <button\n type=\"submit\"\n className=\"lk-wr-submit\"\n disabled={inactive || text.trim().length === 0}\n >\n Submit\n </button>\n <FeedbackRegion id={`${data.id}-feedback`}>{summary}</FeedbackRegion>\n </form>\n );\n}\n","'use client';\n\nimport { ActivityErrorBoundary } from '../ActivityErrorBoundary.js';\nimport {\n WrittenResponse as WrittenResponseCore,\n type WrittenResponseProps,\n} from './WrittenResponse.js';\n\nexport type { WrittenResponseProps, WrittenResponseSubmission } from './WrittenResponse.js';\n\n/**\n * Public Written Response activity: a labelled textarea with a live word\n * counter for free-text writing graded asynchronously (AI or human). The core\n * is wrapped in `ActivityErrorBoundary` so a render failure (incl. the dev\n * schema-validation throw) degrades to an accessible fallback.\n */\nexport function WrittenResponse(props: WrittenResponseProps) {\n return (\n <ActivityErrorBoundary activityTitle={props.data?.title}>\n <WrittenResponseCore {...props} />\n </ActivityErrorBoundary>\n );\n}\n"]}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
require('../chunk-
|
|
5
|
-
require('../chunk-
|
|
6
|
-
require('../chunk-
|
|
3
|
+
var chunkSH7BRP4M_cjs = require('../chunk-SH7BRP4M.cjs');
|
|
4
|
+
require('../chunk-MKH5THDR.cjs');
|
|
5
|
+
require('../chunk-73XCWYKD.cjs');
|
|
6
|
+
require('../chunk-QHOV2A6M.cjs');
|
|
7
7
|
require('../chunk-HD2AIQRD.cjs');
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
Object.defineProperty(exports, "ActivitySequence", {
|
|
12
12
|
enumerable: true,
|
|
13
|
-
get: function () { return
|
|
13
|
+
get: function () { return chunkSH7BRP4M_cjs.ActivitySequence; }
|
|
14
14
|
});
|
|
15
15
|
//# sourceMappingURL=ActivitySequence.cjs.map
|
|
16
16
|
//# sourceMappingURL=ActivitySequence.cjs.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export { ActivitySequence } from '../chunk-
|
|
2
|
-
import '../chunk-
|
|
3
|
-
import '../chunk-
|
|
4
|
-
import '../chunk-
|
|
1
|
+
export { ActivitySequence } from '../chunk-OS7MO2OW.js';
|
|
2
|
+
import '../chunk-G5ZEWJRA.js';
|
|
3
|
+
import '../chunk-32WWQOG3.js';
|
|
4
|
+
import '../chunk-UIGIYYGY.js';
|
|
5
5
|
import '../chunk-5HVUKXF3.js';
|
|
6
6
|
//# sourceMappingURL=ActivitySequence.js.map
|
|
7
7
|
//# sourceMappingURL=ActivitySequence.js.map
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
require('../chunk-
|
|
3
|
+
var chunk73XCWYKD_cjs = require('../chunk-73XCWYKD.cjs');
|
|
4
|
+
require('../chunk-QHOV2A6M.cjs');
|
|
5
5
|
require('../chunk-HD2AIQRD.cjs');
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
Object.defineProperty(exports, "FillInTheBlanks", {
|
|
10
10
|
enumerable: true,
|
|
11
|
-
get: function () { return
|
|
11
|
+
get: function () { return chunk73XCWYKD_cjs.FillInTheBlanks; }
|
|
12
12
|
});
|
|
13
13
|
//# sourceMappingURL=FillInTheBlanks.cjs.map
|
|
14
14
|
//# sourceMappingURL=FillInTheBlanks.cjs.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { FillInTheBlanks } from '../chunk-
|
|
2
|
-
import '../chunk-
|
|
1
|
+
export { FillInTheBlanks } from '../chunk-32WWQOG3.js';
|
|
2
|
+
import '../chunk-UIGIYYGY.js';
|
|
3
3
|
import '../chunk-5HVUKXF3.js';
|
|
4
4
|
//# sourceMappingURL=FillInTheBlanks.js.map
|
|
5
5
|
//# sourceMappingURL=FillInTheBlanks.js.map
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
require('../chunk-
|
|
3
|
+
var chunkMKH5THDR_cjs = require('../chunk-MKH5THDR.cjs');
|
|
4
|
+
require('../chunk-QHOV2A6M.cjs');
|
|
5
5
|
require('../chunk-HD2AIQRD.cjs');
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
Object.defineProperty(exports, "MultipleChoice", {
|
|
10
10
|
enumerable: true,
|
|
11
|
-
get: function () { return
|
|
11
|
+
get: function () { return chunkMKH5THDR_cjs.MultipleChoice; }
|
|
12
12
|
});
|
|
13
13
|
//# sourceMappingURL=MultipleChoice.cjs.map
|
|
14
14
|
//# sourceMappingURL=MultipleChoice.cjs.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { MultipleChoice } from '../chunk-
|
|
2
|
-
import '../chunk-
|
|
1
|
+
export { MultipleChoice } from '../chunk-G5ZEWJRA.js';
|
|
2
|
+
import '../chunk-UIGIYYGY.js';
|
|
3
3
|
import '../chunk-5HVUKXF3.js';
|
|
4
4
|
//# sourceMappingURL=MultipleChoice.js.map
|
|
5
5
|
//# sourceMappingURL=MultipleChoice.js.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkKJNQLAB5_cjs = require('../chunk-KJNQLAB5.cjs');
|
|
4
|
+
require('../chunk-QHOV2A6M.cjs');
|
|
5
|
+
require('../chunk-HD2AIQRD.cjs');
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
Object.defineProperty(exports, "WrittenResponse", {
|
|
10
|
+
enumerable: true,
|
|
11
|
+
get: function () { return chunkKJNQLAB5_cjs.WrittenResponse; }
|
|
12
|
+
});
|
|
13
|
+
//# sourceMappingURL=WrittenResponse.cjs.map
|
|
14
|
+
//# sourceMappingURL=WrittenResponse.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"WrittenResponse.cjs"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { WrittenResponseData, XAPIStatement, InteractionEvent, ThemeTokens } from '@intellectif/lk-core';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Payload delivered when the learner submits a written response. Grading is
|
|
6
|
+
* DEFERRED (asynchronous AI/human grading), so there is no score here — and
|
|
7
|
+
* deliberately no fake one: an ungraded submission must never be shown or
|
|
8
|
+
* stored as a 0. The consumer persists `text` and grades it out-of-band.
|
|
9
|
+
*/
|
|
10
|
+
interface WrittenResponseSubmission {
|
|
11
|
+
/** The submitted text, verbatim. */
|
|
12
|
+
text: string;
|
|
13
|
+
/** Word count of `text`, recomputed with the canonical `countWords()`. */
|
|
14
|
+
wordCount: number;
|
|
15
|
+
/** Whether `wordCount` falls within the activity's `[minWords, maxWords]`. */
|
|
16
|
+
withinWordBounds: boolean;
|
|
17
|
+
/** Time in milliseconds from first interaction to submission. */
|
|
18
|
+
timeSpent: number;
|
|
19
|
+
/** The SUBMITTED-verb xAPI statement built for this submission (no score fields). */
|
|
20
|
+
xapiStatement: XAPIStatement;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Props for {@link WrittenResponse}. Mirrors `ActivityProps` except for the
|
|
24
|
+
* completion callback: a deferred-grading activity completes with a
|
|
25
|
+
* {@link WrittenResponseSubmission} (`onSubmitted`), not a scored
|
|
26
|
+
* `ActivityResult` (`onComplete`) — deviation from Req 22.8 recorded in the
|
|
27
|
+
* roadmap (§3.1): fabricating a score of 0 for ungraded work is the exact
|
|
28
|
+
* bug this type exists to fix.
|
|
29
|
+
*/
|
|
30
|
+
interface WrittenResponseProps {
|
|
31
|
+
data: WrittenResponseData;
|
|
32
|
+
onSubmitted: (submission: WrittenResponseSubmission) => void;
|
|
33
|
+
onInteraction?: (event: InteractionEvent) => void;
|
|
34
|
+
/** Per-instance token overrides, applied as inline CSS vars on the root. */
|
|
35
|
+
theme?: Partial<ThemeTokens>;
|
|
36
|
+
locale?: string;
|
|
37
|
+
disabled?: boolean;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Public Written Response activity: a labelled textarea with a live word
|
|
42
|
+
* counter for free-text writing graded asynchronously (AI or human). The core
|
|
43
|
+
* is wrapped in `ActivityErrorBoundary` so a render failure (incl. the dev
|
|
44
|
+
* schema-validation throw) degrades to an accessible fallback.
|
|
45
|
+
*/
|
|
46
|
+
declare function WrittenResponse(props: WrittenResponseProps): react_jsx_runtime.JSX.Element;
|
|
47
|
+
|
|
48
|
+
export { WrittenResponse, type WrittenResponseProps, type WrittenResponseSubmission };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { WrittenResponseData, XAPIStatement, InteractionEvent, ThemeTokens } from '@intellectif/lk-core';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Payload delivered when the learner submits a written response. Grading is
|
|
6
|
+
* DEFERRED (asynchronous AI/human grading), so there is no score here — and
|
|
7
|
+
* deliberately no fake one: an ungraded submission must never be shown or
|
|
8
|
+
* stored as a 0. The consumer persists `text` and grades it out-of-band.
|
|
9
|
+
*/
|
|
10
|
+
interface WrittenResponseSubmission {
|
|
11
|
+
/** The submitted text, verbatim. */
|
|
12
|
+
text: string;
|
|
13
|
+
/** Word count of `text`, recomputed with the canonical `countWords()`. */
|
|
14
|
+
wordCount: number;
|
|
15
|
+
/** Whether `wordCount` falls within the activity's `[minWords, maxWords]`. */
|
|
16
|
+
withinWordBounds: boolean;
|
|
17
|
+
/** Time in milliseconds from first interaction to submission. */
|
|
18
|
+
timeSpent: number;
|
|
19
|
+
/** The SUBMITTED-verb xAPI statement built for this submission (no score fields). */
|
|
20
|
+
xapiStatement: XAPIStatement;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Props for {@link WrittenResponse}. Mirrors `ActivityProps` except for the
|
|
24
|
+
* completion callback: a deferred-grading activity completes with a
|
|
25
|
+
* {@link WrittenResponseSubmission} (`onSubmitted`), not a scored
|
|
26
|
+
* `ActivityResult` (`onComplete`) — deviation from Req 22.8 recorded in the
|
|
27
|
+
* roadmap (§3.1): fabricating a score of 0 for ungraded work is the exact
|
|
28
|
+
* bug this type exists to fix.
|
|
29
|
+
*/
|
|
30
|
+
interface WrittenResponseProps {
|
|
31
|
+
data: WrittenResponseData;
|
|
32
|
+
onSubmitted: (submission: WrittenResponseSubmission) => void;
|
|
33
|
+
onInteraction?: (event: InteractionEvent) => void;
|
|
34
|
+
/** Per-instance token overrides, applied as inline CSS vars on the root. */
|
|
35
|
+
theme?: Partial<ThemeTokens>;
|
|
36
|
+
locale?: string;
|
|
37
|
+
disabled?: boolean;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Public Written Response activity: a labelled textarea with a live word
|
|
42
|
+
* counter for free-text writing graded asynchronously (AI or human). The core
|
|
43
|
+
* is wrapped in `ActivityErrorBoundary` so a render failure (incl. the dev
|
|
44
|
+
* schema-validation throw) degrades to an accessible fallback.
|
|
45
|
+
*/
|
|
46
|
+
declare function WrittenResponse(props: WrittenResponseProps): react_jsx_runtime.JSX.Element;
|
|
47
|
+
|
|
48
|
+
export { WrittenResponse, type WrittenResponseProps, type WrittenResponseSubmission };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"WrittenResponse.js"}
|
package/dist/hooks/useXAPI.cjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkIYLQSNLE_cjs = require('../chunk-IYLQSNLE.cjs');
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
Object.defineProperty(exports, "useXAPI", {
|
|
8
8
|
enumerable: true,
|
|
9
|
-
get: function () { return
|
|
9
|
+
get: function () { return chunkIYLQSNLE_cjs.useXAPI; }
|
|
10
10
|
});
|
|
11
11
|
//# sourceMappingURL=useXAPI.cjs.map
|
|
12
12
|
//# sourceMappingURL=useXAPI.cjs.map
|
package/dist/hooks/useXAPI.js
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -1,26 +1,31 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
5
|
-
var
|
|
6
|
-
require('./chunk-
|
|
3
|
+
var chunkSH7BRP4M_cjs = require('./chunk-SH7BRP4M.cjs');
|
|
4
|
+
var chunkMKH5THDR_cjs = require('./chunk-MKH5THDR.cjs');
|
|
5
|
+
var chunk73XCWYKD_cjs = require('./chunk-73XCWYKD.cjs');
|
|
6
|
+
var chunkKJNQLAB5_cjs = require('./chunk-KJNQLAB5.cjs');
|
|
7
|
+
require('./chunk-QHOV2A6M.cjs');
|
|
7
8
|
var chunkHD2AIQRD_cjs = require('./chunk-HD2AIQRD.cjs');
|
|
8
|
-
var
|
|
9
|
+
var chunkIYLQSNLE_cjs = require('./chunk-IYLQSNLE.cjs');
|
|
9
10
|
var chunkCPF2JJG6_cjs = require('./chunk-CPF2JJG6.cjs');
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
Object.defineProperty(exports, "ActivitySequence", {
|
|
14
15
|
enumerable: true,
|
|
15
|
-
get: function () { return
|
|
16
|
+
get: function () { return chunkSH7BRP4M_cjs.ActivitySequence; }
|
|
16
17
|
});
|
|
17
18
|
Object.defineProperty(exports, "MultipleChoice", {
|
|
18
19
|
enumerable: true,
|
|
19
|
-
get: function () { return
|
|
20
|
+
get: function () { return chunkMKH5THDR_cjs.MultipleChoice; }
|
|
20
21
|
});
|
|
21
22
|
Object.defineProperty(exports, "FillInTheBlanks", {
|
|
22
23
|
enumerable: true,
|
|
23
|
-
get: function () { return
|
|
24
|
+
get: function () { return chunk73XCWYKD_cjs.FillInTheBlanks; }
|
|
25
|
+
});
|
|
26
|
+
Object.defineProperty(exports, "WrittenResponse", {
|
|
27
|
+
enumerable: true,
|
|
28
|
+
get: function () { return chunkKJNQLAB5_cjs.WrittenResponse; }
|
|
24
29
|
});
|
|
25
30
|
Object.defineProperty(exports, "useActivityState", {
|
|
26
31
|
enumerable: true,
|
|
@@ -28,7 +33,7 @@ Object.defineProperty(exports, "useActivityState", {
|
|
|
28
33
|
});
|
|
29
34
|
Object.defineProperty(exports, "useXAPI", {
|
|
30
35
|
enumerable: true,
|
|
31
|
-
get: function () { return
|
|
36
|
+
get: function () { return chunkIYLQSNLE_cjs.useXAPI; }
|
|
32
37
|
});
|
|
33
38
|
Object.defineProperty(exports, "ThemeProvider", {
|
|
34
39
|
enumerable: true,
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { ActivitySequence, ActivitySequenceProps } from './components/ActivitySequence.cjs';
|
|
2
2
|
export { FillInTheBlanks, FillInTheBlanksProps } from './components/FillInTheBlanks.cjs';
|
|
3
3
|
export { MultipleChoice } from './components/MultipleChoice.cjs';
|
|
4
|
+
export { WrittenResponse, WrittenResponseProps, WrittenResponseSubmission } from './components/WrittenResponse.cjs';
|
|
4
5
|
export { ActivityState, UseActivityStateResult, useActivityState } from './hooks/useActivityState.cjs';
|
|
5
6
|
export { UseXAPIResult, useXAPI } from './hooks/useXAPI.cjs';
|
|
6
7
|
export { ThemeProvider, ThemeProviderProps, darkTheme, defaultTheme, useTheme } from './theme/ThemeProvider.cjs';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { ActivitySequence, ActivitySequenceProps } from './components/ActivitySequence.js';
|
|
2
2
|
export { FillInTheBlanks, FillInTheBlanksProps } from './components/FillInTheBlanks.js';
|
|
3
3
|
export { MultipleChoice } from './components/MultipleChoice.js';
|
|
4
|
+
export { WrittenResponse, WrittenResponseProps, WrittenResponseSubmission } from './components/WrittenResponse.js';
|
|
4
5
|
export { ActivityState, UseActivityStateResult, useActivityState } from './hooks/useActivityState.js';
|
|
5
6
|
export { UseXAPIResult, useXAPI } from './hooks/useXAPI.js';
|
|
6
7
|
export { ThemeProvider, ThemeProviderProps, darkTheme, defaultTheme, useTheme } from './theme/ThemeProvider.js';
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
export { ActivitySequence } from './chunk-
|
|
2
|
-
export { MultipleChoice } from './chunk-
|
|
3
|
-
export { FillInTheBlanks } from './chunk-
|
|
4
|
-
|
|
1
|
+
export { ActivitySequence } from './chunk-OS7MO2OW.js';
|
|
2
|
+
export { MultipleChoice } from './chunk-G5ZEWJRA.js';
|
|
3
|
+
export { FillInTheBlanks } from './chunk-32WWQOG3.js';
|
|
4
|
+
export { WrittenResponse } from './chunk-V5EN3ESV.js';
|
|
5
|
+
import './chunk-UIGIYYGY.js';
|
|
5
6
|
export { useActivityState } from './chunk-5HVUKXF3.js';
|
|
6
|
-
export { useXAPI } from './chunk-
|
|
7
|
+
export { useXAPI } from './chunk-E4MNA2IQ.js';
|
|
7
8
|
export { ThemeProvider, darkTheme, defaultTheme, useTheme } from './chunk-B3FUUKZ2.js';
|
|
8
9
|
//# sourceMappingURL=index.js.map
|
|
9
10
|
//# sourceMappingURL=index.js.map
|
package/dist/theme/skin.css
CHANGED
|
@@ -349,4 +349,89 @@
|
|
|
349
349
|
color: var(--lk-color-text-muted);
|
|
350
350
|
font-size: var(--lk-font-size-sm);
|
|
351
351
|
}
|
|
352
|
+
|
|
353
|
+
/* ── Written Response ────────────────────────────────────────────────── */
|
|
354
|
+
.lk-wr {
|
|
355
|
+
display: flex;
|
|
356
|
+
flex-direction: column;
|
|
357
|
+
gap: var(--lk-spacing-md);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
.lk-wr-prompt {
|
|
361
|
+
margin: 0;
|
|
362
|
+
color: var(--lk-color-text);
|
|
363
|
+
font-family: var(--lk-font-family);
|
|
364
|
+
font-size: var(--lk-font-size-base);
|
|
365
|
+
line-height: 1.6;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
.lk-wr-textarea {
|
|
369
|
+
width: 100%;
|
|
370
|
+
padding: var(--lk-spacing-sm) var(--lk-spacing-md);
|
|
371
|
+
border: 1px solid var(--lk-color-border);
|
|
372
|
+
border-radius: var(--lk-border-radius-md);
|
|
373
|
+
background: var(--lk-color-surface);
|
|
374
|
+
color: var(--lk-color-text);
|
|
375
|
+
font-family: var(--lk-font-family);
|
|
376
|
+
font-size: var(--lk-font-size-base);
|
|
377
|
+
line-height: 1.5;
|
|
378
|
+
resize: vertical;
|
|
379
|
+
transition: var(--lk-transition-fast);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
.lk-wr-textarea:disabled {
|
|
383
|
+
opacity: 0.7;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
.lk-wr-counter {
|
|
387
|
+
color: var(--lk-color-text-muted);
|
|
388
|
+
font-size: var(--lk-font-size-sm);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
.lk-wr-counter[data-within-bounds="true"] {
|
|
392
|
+
color: var(--lk-color-success);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
.lk-wr button[type="submit"] {
|
|
396
|
+
align-self: flex-start;
|
|
397
|
+
padding: var(--lk-spacing-sm) var(--lk-spacing-lg);
|
|
398
|
+
border: none;
|
|
399
|
+
border-radius: var(--lk-border-radius-md);
|
|
400
|
+
background: var(--lk-color-primary);
|
|
401
|
+
color: var(--lk-color-on-primary);
|
|
402
|
+
font-family: var(--lk-font-family);
|
|
403
|
+
font-size: var(--lk-font-size-base);
|
|
404
|
+
cursor: pointer;
|
|
405
|
+
transition: var(--lk-transition-fast);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
.lk-wr button[type="submit"]:hover:not(:disabled) {
|
|
409
|
+
background: var(--lk-color-primary-hover);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
.lk-wr button[type="submit"]:disabled {
|
|
413
|
+
opacity: 0.55;
|
|
414
|
+
cursor: default;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
.lk-wr :focus-visible {
|
|
418
|
+
outline: 2px solid var(--lk-color-focus-ring);
|
|
419
|
+
outline-offset: 2px;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
.lk-wr > [aria-live] {
|
|
423
|
+
color: var(--lk-color-text-muted);
|
|
424
|
+
font-size: var(--lk-font-size-sm);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/* ── Reduced motion (WCAG 2.3.3) ─────────────────────────────────────── */
|
|
428
|
+
@media (prefers-reduced-motion: reduce) {
|
|
429
|
+
.lk-mc *,
|
|
430
|
+
.lk-fib *,
|
|
431
|
+
.lk-wr *,
|
|
432
|
+
.lk-seq * {
|
|
433
|
+
transition: none;
|
|
434
|
+
animation: none;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
352
437
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intellectif/lk-react",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "React 19 activity components, hooks, and theming for learning-kit",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/intellectif/learning-kit.git",
|
|
8
|
+
"directory": "packages/lk-react"
|
|
9
|
+
},
|
|
5
10
|
"type": "module",
|
|
6
11
|
"sideEffects": [
|
|
7
12
|
"**/*.css"
|
|
@@ -27,6 +32,11 @@
|
|
|
27
32
|
"import": "./dist/components/FillInTheBlanks.js",
|
|
28
33
|
"require": "./dist/components/FillInTheBlanks.cjs"
|
|
29
34
|
},
|
|
35
|
+
"./components/WrittenResponse": {
|
|
36
|
+
"types": "./dist/components/WrittenResponse.d.ts",
|
|
37
|
+
"import": "./dist/components/WrittenResponse.js",
|
|
38
|
+
"require": "./dist/components/WrittenResponse.cjs"
|
|
39
|
+
},
|
|
30
40
|
"./hooks/useActivityState": {
|
|
31
41
|
"types": "./dist/hooks/useActivityState.d.ts",
|
|
32
42
|
"import": "./dist/hooks/useActivityState.js",
|
|
@@ -49,12 +59,13 @@
|
|
|
49
59
|
"module": "./dist/index.js",
|
|
50
60
|
"types": "./dist/index.d.ts",
|
|
51
61
|
"files": [
|
|
52
|
-
"dist"
|
|
62
|
+
"dist",
|
|
63
|
+
"LICENSE"
|
|
53
64
|
],
|
|
54
65
|
"peerDependencies": {
|
|
55
66
|
"react": "^19",
|
|
56
67
|
"react-dom": "^19",
|
|
57
|
-
"@intellectif/lk-core": "^0.
|
|
68
|
+
"@intellectif/lk-core": "^0.3.0"
|
|
58
69
|
},
|
|
59
70
|
"devDependencies": {
|
|
60
71
|
"@axe-core/react": "^4.10.0",
|
|
@@ -73,9 +84,12 @@
|
|
|
73
84
|
"tsup": "^8.3.0",
|
|
74
85
|
"vitest": "^4.1.6",
|
|
75
86
|
"vitest-axe": "^0.1.0",
|
|
76
|
-
"@intellectif/lk-core": "0.
|
|
87
|
+
"@intellectif/lk-core": "0.3.0"
|
|
77
88
|
},
|
|
78
89
|
"license": "MIT",
|
|
90
|
+
"engines": {
|
|
91
|
+
"node": ">=20"
|
|
92
|
+
},
|
|
79
93
|
"scripts": {
|
|
80
94
|
"build": "tsup",
|
|
81
95
|
"test": "vitest run",
|