@superbuilders/incept-renderer 0.1.8 → 0.1.12
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 +537 -14
- package/dist/actions/index.d.ts +4 -1
- package/dist/actions/index.js +65 -6
- package/dist/actions/index.js.map +1 -1
- package/dist/components/index.d.ts +2 -3
- package/dist/components/index.js +43 -28
- package/dist/components/index.js.map +1 -1
- package/dist/index.d.ts +6 -11
- package/dist/index.js +94 -28
- package/dist/index.js.map +1 -1
- package/dist/parser-B8n3iHSM.d.ts +29 -0
- package/dist/qti-stimulus-renderer-CSuLfoff.d.ts +178 -0
- package/dist/{schema-DZoGAQdF.d.ts → schema-DKduufCs.d.ts} +106 -128
- package/dist/styles/duolingo.css +221 -0
- package/dist/styles/duolingo.css.map +1 -0
- package/dist/styles/duolingo.d.ts +2 -0
- package/dist/styles/themes.css +573 -37
- package/dist/styles/themes.css.map +1 -1
- package/dist/types.d.ts +2 -2
- package/package.json +5 -1
- package/dist/types-B7YRTQKt.d.ts +0 -102
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export { a as DisplayBlock,
|
|
1
|
+
export { C as ChoiceCorrectness, d as ContentBlockRenderer, a as ContentBlockRendererProps, e as QTIRenderer, Q as QTIRendererProps, f as QTIStimulusRenderer, b as QTIStimulusRendererProps, c as QTITheme, R as ResponseFeedback } from './qti-stimulus-renderer-CSuLfoff.js';
|
|
2
|
+
import { A as AssessmentItem } from './schema-DKduufCs.js';
|
|
3
|
+
export { c as AnyInteraction, n as AssessmentItemSchema, a as AssessmentStimulus, o as AssessmentStimulusSchema, C as ChoiceInteraction, e as DisplayBlock, f as DisplayChoice, g as DisplayChoiceInteraction, k as DisplayItem, F as FeedbackBlock, m as FormShape, R as ResponseDeclaration, d as ResponseProcessing, V as ValidateResult } from './schema-DKduufCs.js';
|
|
4
|
+
import { N as NormalizedNode } from './parser-B8n3iHSM.js';
|
|
5
|
+
export { p as parseAssessmentItemXml, a as parseAssessmentStimulusXml } from './parser-B8n3iHSM.js';
|
|
4
6
|
import 'react/jsx-runtime';
|
|
5
7
|
import 'zod';
|
|
6
8
|
|
|
@@ -9,13 +11,6 @@ import 'zod';
|
|
|
9
11
|
*/
|
|
10
12
|
declare function evaluateFeedbackIdentifiers(item: AssessmentItem, responses: Record<string, string | string[]>, responseResults: Record<string, boolean>): string[];
|
|
11
13
|
|
|
12
|
-
interface NormalizedNode {
|
|
13
|
-
tagName: string;
|
|
14
|
-
attrs: Record<string, unknown>;
|
|
15
|
-
children: Array<NormalizedNode | string>;
|
|
16
|
-
}
|
|
17
|
-
declare function parseAssessmentItemXml(xml: string): AssessmentItem;
|
|
18
|
-
|
|
19
14
|
/**
|
|
20
15
|
* Configuration for HTML sanitization.
|
|
21
16
|
* Defines allowed tags and attributes for safe rendering.
|
|
@@ -56,4 +51,4 @@ declare function serializeNode(node: NormalizedNode): string;
|
|
|
56
51
|
*/
|
|
57
52
|
declare function detectContentType(html: string): "mathml" | "html";
|
|
58
53
|
|
|
59
|
-
export { AssessmentItem, detectContentType, evaluateFeedbackIdentifiers,
|
|
54
|
+
export { AssessmentItem, detectContentType, evaluateFeedbackIdentifiers, sanitizeForDisplay, sanitizeHtml, serializeInner, serializeNode, serializeNodes };
|
package/dist/index.js
CHANGED
|
@@ -33,6 +33,13 @@ var DEFAULT_CONFIG = {
|
|
|
33
33
|
"div",
|
|
34
34
|
"br",
|
|
35
35
|
"hr",
|
|
36
|
+
// Headings
|
|
37
|
+
"h1",
|
|
38
|
+
"h2",
|
|
39
|
+
"h3",
|
|
40
|
+
"h4",
|
|
41
|
+
"h5",
|
|
42
|
+
"h6",
|
|
36
43
|
// Formatting
|
|
37
44
|
"b",
|
|
38
45
|
"i",
|
|
@@ -82,6 +89,9 @@ var DEFAULT_CONFIG = {
|
|
|
82
89
|
"figcaption",
|
|
83
90
|
"blockquote",
|
|
84
91
|
"cite",
|
|
92
|
+
// Interactive
|
|
93
|
+
"details",
|
|
94
|
+
"summary",
|
|
85
95
|
// Links
|
|
86
96
|
"a",
|
|
87
97
|
// Forms (for future interactive elements)
|
|
@@ -480,7 +490,7 @@ var choiceIndicatorVariants = cva(
|
|
|
480
490
|
"data-[state=unchecked]:bg-background data-[state=unchecked]:border-2 data-[state=unchecked]:border-input data-[state=unchecked]:text-muted-foreground",
|
|
481
491
|
"data-[state=checked]:border-2 data-[state=checked]:border-[var(--choice-complement)] data-[state=checked]:text-[var(--choice-foreground)]",
|
|
482
492
|
"data-[filled=true]:data-[state=checked]:bg-[var(--choice-complement)]",
|
|
483
|
-
"data-[filled=true]:data-[state=checked]:shadow-[
|
|
493
|
+
"data-[filled=true]:data-[state=checked]:shadow-[inset_0_0_0_3px_rgb(255_255_255)] dark:data-[filled=true]:data-[state=checked]:shadow-[inset_0_0_0_3px_hsl(var(--background))]",
|
|
484
494
|
"focus-visible:ring-[var(--choice-complement)] focus-visible:ring-[3px]",
|
|
485
495
|
"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive"
|
|
486
496
|
],
|
|
@@ -509,31 +519,38 @@ function ChoiceIndicator({
|
|
|
509
519
|
letter,
|
|
510
520
|
type = "radio",
|
|
511
521
|
showLetter = true,
|
|
512
|
-
|
|
522
|
+
id,
|
|
523
|
+
value,
|
|
524
|
+
checked,
|
|
525
|
+
onCheckedChange,
|
|
526
|
+
disabled
|
|
513
527
|
}) {
|
|
514
528
|
const baseClassName = cn(choiceIndicatorVariants({ palette }), className);
|
|
515
529
|
if (type === "checkbox") {
|
|
516
|
-
const checkboxProps = props;
|
|
517
530
|
return /* @__PURE__ */ jsx(
|
|
518
531
|
CheckboxPrimitive.Root,
|
|
519
532
|
{
|
|
520
533
|
"data-slot": "choice-indicator",
|
|
521
534
|
"data-palette": palette,
|
|
522
|
-
"data-filled": !showLetter,
|
|
535
|
+
"data-filled": !showLetter ? "true" : void 0,
|
|
523
536
|
className: baseClassName,
|
|
524
|
-
|
|
537
|
+
id,
|
|
538
|
+
checked,
|
|
539
|
+
onCheckedChange,
|
|
540
|
+
disabled,
|
|
525
541
|
children: showLetter && /* @__PURE__ */ jsx("span", { className: "data-[state=unchecked]:block data-[state=checked]:hidden", children: letter })
|
|
526
542
|
}
|
|
527
543
|
);
|
|
528
544
|
}
|
|
529
|
-
const radioProps = props;
|
|
530
545
|
return /* @__PURE__ */ jsx(
|
|
531
546
|
RadioGroupPrimitive.Item,
|
|
532
547
|
{
|
|
533
548
|
"data-slot": "choice-indicator",
|
|
534
549
|
"data-palette": palette,
|
|
535
550
|
className: baseClassName,
|
|
536
|
-
|
|
551
|
+
id,
|
|
552
|
+
value: value ?? "",
|
|
553
|
+
disabled,
|
|
537
554
|
children: letter
|
|
538
555
|
}
|
|
539
556
|
);
|
|
@@ -1886,14 +1903,16 @@ function SortableItem({
|
|
|
1886
1903
|
style,
|
|
1887
1904
|
...attributes,
|
|
1888
1905
|
...listeners,
|
|
1906
|
+
"data-disabled": disabled,
|
|
1907
|
+
"data-dragging": isDragging,
|
|
1889
1908
|
className: cn(
|
|
1890
|
-
"
|
|
1909
|
+
"qti-order-item",
|
|
1891
1910
|
// Styling differs based on orientation
|
|
1892
|
-
isHorizontal ? "
|
|
1893
|
-
disabled ? "cursor-default
|
|
1911
|
+
isHorizontal ? "min-w-[100px] flex items-center justify-center text-center" : "w-full flex items-center gap-3",
|
|
1912
|
+
disabled ? "cursor-default" : "cursor-grab active:cursor-grabbing"
|
|
1894
1913
|
),
|
|
1895
1914
|
children: [
|
|
1896
|
-
!isHorizontal && /* @__PURE__ */ jsx("div", { className: "
|
|
1915
|
+
!isHorizontal && /* @__PURE__ */ jsx("div", { className: "qti-order-item-handle shrink-0", children: /* @__PURE__ */ jsx(DragHandleIcon, {}) }),
|
|
1897
1916
|
/* @__PURE__ */ jsx(HTMLContent, { html: contentHtml })
|
|
1898
1917
|
]
|
|
1899
1918
|
}
|
|
@@ -1903,12 +1922,13 @@ function DragOverlayItem({ contentHtml, isHorizontal }) {
|
|
|
1903
1922
|
return /* @__PURE__ */ jsxs(
|
|
1904
1923
|
"div",
|
|
1905
1924
|
{
|
|
1925
|
+
"data-dragging": "true",
|
|
1906
1926
|
className: cn(
|
|
1907
|
-
"
|
|
1908
|
-
isHorizontal ? "
|
|
1927
|
+
"qti-order-item cursor-grabbing z-50",
|
|
1928
|
+
isHorizontal ? "min-w-[100px] flex items-center justify-center" : "w-full flex items-center gap-3"
|
|
1909
1929
|
),
|
|
1910
1930
|
children: [
|
|
1911
|
-
!isHorizontal && /* @__PURE__ */ jsx("div", { className: "
|
|
1931
|
+
!isHorizontal && /* @__PURE__ */ jsx("div", { className: "qti-order-item-handle shrink-0", children: /* @__PURE__ */ jsx(DragHandleIcon, {}) }),
|
|
1912
1932
|
/* @__PURE__ */ jsx(HTMLContent, { html: contentHtml })
|
|
1913
1933
|
]
|
|
1914
1934
|
}
|
|
@@ -1962,14 +1982,9 @@ function OrderInteraction({
|
|
|
1962
1982
|
styles: { active: { opacity: "0.4" } }
|
|
1963
1983
|
})
|
|
1964
1984
|
};
|
|
1965
|
-
const
|
|
1966
|
-
if (!hasSubmitted)
|
|
1967
|
-
|
|
1968
|
-
}
|
|
1969
|
-
if (isCorrect) {
|
|
1970
|
-
return "bg-owl/10 border-owl";
|
|
1971
|
-
}
|
|
1972
|
-
return "bg-cardinal/10 border-cardinal";
|
|
1985
|
+
const getContainerCorrectness = () => {
|
|
1986
|
+
if (!hasSubmitted) return void 0;
|
|
1987
|
+
return isCorrect;
|
|
1973
1988
|
};
|
|
1974
1989
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
1975
1990
|
interaction.promptHtml && /* @__PURE__ */ jsx(HTMLContent, { html: interaction.promptHtml }),
|
|
@@ -1984,11 +1999,8 @@ function OrderInteraction({
|
|
|
1984
1999
|
/* @__PURE__ */ jsx(SortableContext, { items: items.map((i) => i.id), strategy, disabled: disabled || hasSubmitted, children: /* @__PURE__ */ jsx(
|
|
1985
2000
|
"div",
|
|
1986
2001
|
{
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
isHorizontal ? "flex flex-wrap gap-3" : "flex flex-col gap-2",
|
|
1990
|
-
getContainerStyles()
|
|
1991
|
-
),
|
|
2002
|
+
"data-correct": getContainerCorrectness(),
|
|
2003
|
+
className: cn("qti-order-container", isHorizontal ? "flex flex-wrap" : "flex flex-col"),
|
|
1992
2004
|
children: items.map((item) => /* @__PURE__ */ jsx(
|
|
1993
2005
|
SortableItem,
|
|
1994
2006
|
{
|
|
@@ -2538,6 +2550,9 @@ function QTIRenderer({
|
|
|
2538
2550
|
showFeedback && overallFeedback?.messageHtml && /* @__PURE__ */ jsx("div", { className: "qti-feedback mt-6 p-6", "data-correct": overallFeedback.isCorrect, children: /* @__PURE__ */ jsx(HTMLContent, { html: overallFeedback.messageHtml }) })
|
|
2539
2551
|
] });
|
|
2540
2552
|
}
|
|
2553
|
+
function QTIStimulusRenderer({ stimulus, className }) {
|
|
2554
|
+
return /* @__PURE__ */ jsx("article", { className: cn("qti-stimulus", className), lang: stimulus.xmlLang, "data-stimulus-id": stimulus.identifier, children: /* @__PURE__ */ jsx(HTMLContent, { html: stimulus.bodyHtml, className: "qti-stimulus-body" }) });
|
|
2555
|
+
}
|
|
2541
2556
|
function normalizeString(str, caseSensitive) {
|
|
2542
2557
|
const s = (str ?? "").trim();
|
|
2543
2558
|
return caseSensitive ? s : s.toLowerCase();
|
|
@@ -2956,6 +2971,16 @@ var AssessmentItemSchema = z.object({
|
|
|
2956
2971
|
itemBody: ItemBodySchema,
|
|
2957
2972
|
responseProcessing: ResponseProcessingSchema
|
|
2958
2973
|
});
|
|
2974
|
+
var AssessmentStimulusSchema = z.object({
|
|
2975
|
+
/** Unique identifier for the stimulus */
|
|
2976
|
+
identifier: z.string().min(1),
|
|
2977
|
+
/** Human-readable title */
|
|
2978
|
+
title: z.string().default(""),
|
|
2979
|
+
/** Language code (e.g., "en", "es") */
|
|
2980
|
+
xmlLang: z.string().default("en"),
|
|
2981
|
+
/** The HTML content of the stimulus body */
|
|
2982
|
+
bodyHtml: z.string()
|
|
2983
|
+
});
|
|
2959
2984
|
|
|
2960
2985
|
// src/parser.ts
|
|
2961
2986
|
function createXmlParser() {
|
|
@@ -3581,7 +3606,48 @@ function parseAssessmentItemXml(xml) {
|
|
|
3581
3606
|
}
|
|
3582
3607
|
return validation.data;
|
|
3583
3608
|
}
|
|
3609
|
+
function parseAssessmentStimulusXml(xml) {
|
|
3610
|
+
if (!xml || typeof xml !== "string") {
|
|
3611
|
+
throw errors.new("xml input must be a non-empty string");
|
|
3612
|
+
}
|
|
3613
|
+
const parser = createXmlParser();
|
|
3614
|
+
const parseResult = errors.trySync(() => {
|
|
3615
|
+
return parser.parse(xml, true);
|
|
3616
|
+
});
|
|
3617
|
+
if (parseResult.error) {
|
|
3618
|
+
throw errors.wrap(parseResult.error, "xml parse");
|
|
3619
|
+
}
|
|
3620
|
+
const raw = parseResult.data;
|
|
3621
|
+
if (!Array.isArray(raw)) {
|
|
3622
|
+
throw errors.new("expected xml parser to output an array for preserveOrder");
|
|
3623
|
+
}
|
|
3624
|
+
const normalizedTree = raw.map(normalizeNode).filter((n) => typeof n !== "string");
|
|
3625
|
+
const rootNode = normalizedTree.find(
|
|
3626
|
+
(n) => n.tagName === "qti-assessment-stimulus" || n.tagName.endsWith("assessment-stimulus")
|
|
3627
|
+
);
|
|
3628
|
+
if (!rootNode) {
|
|
3629
|
+
throw errors.new("qti assessment stimulus not found in xml document");
|
|
3630
|
+
}
|
|
3631
|
+
const rootChildren = rootNode.children.filter((c) => typeof c !== "string");
|
|
3632
|
+
const stimulusBodyNode = rootChildren.find((n) => n.tagName === "qti-stimulus-body");
|
|
3633
|
+
if (!stimulusBodyNode) {
|
|
3634
|
+
throw errors.new("qti-stimulus-body not found in stimulus document");
|
|
3635
|
+
}
|
|
3636
|
+
const bodyHtml = getInnerHtml(stimulusBodyNode);
|
|
3637
|
+
const normalizedStimulus = {
|
|
3638
|
+
identifier: coerceString(rootNode.attrs.identifier),
|
|
3639
|
+
title: coerceString(rootNode.attrs.title),
|
|
3640
|
+
xmlLang: coerceString(rootNode.attrs["xml:lang"]) || coerceString(rootNode.attrs["xml-lang"]) || "en",
|
|
3641
|
+
bodyHtml
|
|
3642
|
+
};
|
|
3643
|
+
const validation = AssessmentStimulusSchema.safeParse(normalizedStimulus);
|
|
3644
|
+
if (!validation.success) {
|
|
3645
|
+
const errorDetails = validation.error.issues.map((err) => `${err.path.join(".")}: ${err.message}`).join("; ");
|
|
3646
|
+
throw errors.new(`qti stimulus validation: ${errorDetails}`);
|
|
3647
|
+
}
|
|
3648
|
+
return validation.data;
|
|
3649
|
+
}
|
|
3584
3650
|
|
|
3585
|
-
export { AssessmentItemSchema, ContentBlockRenderer, QTIRenderer, detectContentType, evaluateFeedbackIdentifiers, parseAssessmentItemXml, sanitizeForDisplay, sanitizeHtml, serializeInner, serializeNode, serializeNodes };
|
|
3651
|
+
export { AssessmentItemSchema, AssessmentStimulusSchema, ContentBlockRenderer, QTIRenderer, QTIStimulusRenderer, detectContentType, evaluateFeedbackIdentifiers, parseAssessmentItemXml, parseAssessmentStimulusXml, sanitizeForDisplay, sanitizeHtml, serializeInner, serializeNode, serializeNodes };
|
|
3586
3652
|
//# sourceMappingURL=index.js.map
|
|
3587
3653
|
//# sourceMappingURL=index.js.map
|