@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/dist/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
- import { d as AssessmentItem } from './schema-DZoGAQdF.js';
2
- export { c as AnyInteraction, j as AssessmentItemSchema, C as ChoiceCorrectness, e as ChoiceInteraction, h as ContentBlockRenderer, a as ContentBlockRendererProps, F as FeedbackBlock, i as QTIRenderer, Q as QTIRendererProps, b as QTITheme, f as ResponseDeclaration, R as ResponseFeedback, g as ResponseProcessing } from './schema-DZoGAQdF.js';
3
- export { a as DisplayBlock, b as DisplayChoice, c as DisplayChoiceInteraction, g as DisplayItem, F as FormShape, V as ValidateResult } from './types-B7YRTQKt.js';
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, parseAssessmentItemXml, sanitizeForDisplay, sanitizeHtml, serializeInner, serializeNode, serializeNodes };
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-[inset_0_0_0_2px_rgb(255_255_255)] dark:data-[filled=true]:data-[state=checked]:shadow-[inset_0_0_0_2px_rgb(255_255_255)]",
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
- ...props
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
- ...checkboxProps,
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
- ...radioProps,
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
- "bg-background border rounded-lg shadow-sm touch-none select-none",
1909
+ "qti-order-item",
1891
1910
  // Styling differs based on orientation
1892
- isHorizontal ? "px-4 py-2 min-w-[100px] flex items-center justify-center text-center" : "p-4 w-full flex items-center gap-3",
1893
- disabled ? "cursor-default opacity-90 bg-muted/50" : "cursor-grab active:cursor-grabbing hover:border-macaw/50 hover:shadow-md"
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: "text-muted-foreground shrink-0", children: /* @__PURE__ */ jsx(DragHandleIcon, {}) }),
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
- "bg-background border-2 border-macaw rounded-lg shadow-xl cursor-grabbing z-50",
1908
- isHorizontal ? "px-4 py-2 min-w-[100px] flex items-center justify-center" : "p-4 w-full flex items-center gap-3"
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: "text-macaw shrink-0", children: /* @__PURE__ */ jsx(DragHandleIcon, {}) }),
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 getContainerStyles = () => {
1966
- if (!hasSubmitted) {
1967
- return "bg-muted/30 border-transparent";
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
- className: cn(
1988
- "rounded-xl p-4 transition-colors border-2",
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