@citolab/qti-components 7.0.2 → 7.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/item.css CHANGED
@@ -2346,20 +2346,6 @@ qti-response-declaration {
2346
2346
 
2347
2347
  & qti-gap {
2348
2348
 
2349
- &[enabled] {
2350
-
2351
- /* Light theme override */
2352
- .qti-selections-light & {
2353
- border-color: var(--qti-light-border-active);
2354
- }
2355
-
2356
- /* Dark theme override */
2357
- .qti-selections-dark & {
2358
- border-color: var(--qti-dark-border-active);
2359
- }
2360
- background-color: var(--qti-bg-active)
2361
- }
2362
-
2363
2349
  &[disabled] {
2364
2350
 
2365
2351
  &:not(:empty) {
@@ -2377,6 +2363,20 @@ qti-response-declaration {
2377
2363
  outline: 4px solid var(--qti-disabled-bg)
2378
2364
  }
2379
2365
 
2366
+ &[enabled] {
2367
+
2368
+ /* Light theme override */
2369
+ .qti-selections-light & {
2370
+ border-color: var(--qti-light-border-active);
2371
+ }
2372
+
2373
+ /* Dark theme override */
2374
+ .qti-selections-dark & {
2375
+ border-color: var(--qti-dark-border-active);
2376
+ }
2377
+ background-color: var(--qti-bg-active)
2378
+ }
2379
+
2380
2380
  &[active] {
2381
2381
 
2382
2382
  /* Light theme override */
@@ -2759,12 +2759,22 @@ qti-response-declaration {
2759
2759
  }
2760
2760
 
2761
2761
  qti-match-interaction:not(.qti-match-tabular) {
2762
+ &:state(--dragzone-enabled) qti-simple-match-set:first-of-type {
2763
+ background-color: var(--qti-bg-active);
2764
+ }
2765
+
2766
+ &:state(--dragzone-active) qti-simple-match-set:first-of-type {
2767
+ border-color: var(--qti-border-active);
2768
+ background-color: var(--qti-bg-active);
2769
+ }
2770
+
2762
2771
  /* The draggables */
2763
2772
  & qti-simple-match-set:first-of-type {
2764
2773
  display: flex;
2765
2774
  flex-wrap: wrap;
2766
2775
  align-items: flex-start; /* Prevents children from stretching */
2767
2776
  gap: var(--qti-gap-size);
2777
+ border: 2px solid transparent;
2768
2778
 
2769
2779
  & qti-simple-associable-choice {
2770
2780
 
@@ -3156,6 +3166,16 @@ qti-response-declaration {
3156
3166
  }
3157
3167
 
3158
3168
  qti-associate-interaction {
3169
+ /* General styles for active and enabled states */
3170
+ &:state(--dragzone-active) slot[name='qti-simple-associable-choice'] {
3171
+ border-color: var(--qti-border-active);
3172
+ background-color: var(--qti-bg-active);
3173
+ }
3174
+
3175
+ &:state(--dragzone-enabled) slot[name='qti-simple-associable-choice'] {
3176
+ background-color: var(--qti-bg-active);
3177
+ }
3178
+
3159
3179
  & qti-simple-associable-choice, /* drags when in lightdom */
3160
3180
  &::part(qti-simple-associable-choice) /* drags when in shadowdom */ {
3161
3181
 
@@ -3458,76 +3478,8 @@ qti-response-declaration {
3458
3478
  }
3459
3479
 
3460
3480
  qti-slider-interaction {
3461
- display: block;
3462
-
3463
3481
  --qti-tick-color: rgb(229 231 235 / 100%);
3464
3482
  --qti-tick-width: 1px;
3465
-
3466
- &::part(slider) {
3467
- margin-left: 2rem; /* mx-8 */
3468
- margin-right: 2rem;
3469
- padding-bottom: 1rem; /* pb-4 */
3470
- padding-top: 1.25rem; /* pt-5 */
3471
- }
3472
-
3473
- --show-bounds: true;
3474
-
3475
- &::part(bounds) {
3476
- display: flex;
3477
- width: 100%;
3478
- justify-content: space-between;
3479
- margin-bottom: 0.5rem; /* mb-2 */
3480
- }
3481
-
3482
- --show-ticks: true;
3483
-
3484
- &::part(ticks) {
3485
- margin-left: 0.125rem; /* mx-0.5 */
3486
- margin-right: 0.125rem;
3487
- margin-bottom: 0.25rem; /* mb-1 */
3488
- height: 0.5rem; /* h-2 */
3489
- background: linear-gradient(to right, var(--qti-tick-color) var(--qti-tick-width), transparent 1px) repeat-x 0
3490
- center / calc(calc(100% - var(--qti-tick-width)) / ((var(--max) - var(--min)) / var(--step))) 100%;
3491
- }
3492
-
3493
- &::part(rail) {
3494
- display: flex;
3495
- align-items: center;
3496
- box-sizing: border-box;
3497
- height: 0.375rem; /* h-1.5 */
3498
- width: 100%;
3499
- cursor: pointer;
3500
- border-radius: 9999px; /* rounded-full */
3501
- border: 1px solid #d1d5db; /* border-gray-300 */
3502
- background-color: #e5e7eb; /* bg-gray-200 */
3503
- }
3504
-
3505
- &::part(knob) {
3506
- background-color: var(--qti-primary);
3507
- position: relative;
3508
- height: 1rem; /* h-4 */
3509
- width: 1rem; /* w-4 */
3510
- transform-origin: center;
3511
- transform: translateX(-50%);
3512
- cursor: pointer;
3513
- border-radius: 9999px; /* rounded-full */
3514
- left: var(--value-percentage);
3515
- }
3516
-
3517
- --show-value: true;
3518
-
3519
- &::part(value) {
3520
- position: absolute;
3521
- bottom: 2rem; /* bottom-8 */
3522
- left: 0.5rem; /* left-2 */
3523
- transform: translateX(-50%);
3524
- cursor: pointer;
3525
- border-radius: 0.25rem; /* rounded */
3526
- background-color: #f3f4f6; /* bg-gray-100 */
3527
- padding: 0.25rem 0.5rem; /* px-2 py-1 */
3528
- text-align: center;
3529
- color: #6b7280; /* text-gray-500 */
3530
- }
3531
3483
  }
3532
3484
 
3533
3485
  qti-select-point-interaction {
@@ -1,4 +1,4 @@
1
- import { e as QtiAssessmentItem } from '../qti-simple-choice-DG8ImdPz.js';
1
+ import { e as QtiAssessmentItem } from '../qti-simple-choice-D0GiMrqD.js';
2
2
  import 'lit-html';
3
3
  import 'lit';
4
4
  import 'lit-html/directives/ref.js';
@@ -250,6 +250,7 @@ var qtiTransformTest = () => {
250
250
  return new Promise((resolve, _) => {
251
251
  loadXML(uri).then((xml2) => {
252
252
  xmlFragment = xml2;
253
+ api.path(uri.substring(0, uri.lastIndexOf("/")));
253
254
  return resolve(api);
254
255
  });
255
256
  });
@@ -258,6 +259,10 @@ var qtiTransformTest = () => {
258
259
  xmlFragment = parseXML(xmlString);
259
260
  return api;
260
261
  },
262
+ path: (location) => {
263
+ setLocation(xmlFragment, location);
264
+ return api;
265
+ },
261
266
  fn(fn) {
262
267
  fn(xmlFragment);
263
268
  return api;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/lib/qti-transformers/qti-transformers.ts","../../src/lib/qti-transformers/qti-transform-item.ts","../../src/lib/qti-transformers/qti-transform-manifest.ts","../../src/lib/qti-transformers/qti-transform-test.ts","../../src/lib/qti-loader/qti-loader.ts"],"sourcesContent":["const xml = String.raw;\n\n/* <!-- convert CDATA to comments -->\n <xsl:template match=\"text()[contains(., 'CDATA')]\">\n <xsl:comment>\n <xsl:value-of select=\".\"/>\n </xsl:comment>\n</xsl:template>\n*/\n\n/*\n <!-- remove xml comments -->\n <xsl:template match=\"comment()\" />\n */\n\nconst xmlToHTML = xml`<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">\n<xsl:output method=\"html\" version=\"5.0\" encoding=\"UTF-8\" indent=\"yes\" />\n <xsl:template match=\"@*|node()\">\n <xsl:copy>\n <xsl:apply-templates select=\"@*|node()\"/>\n </xsl:copy>\n </xsl:template>\n\n <!-- remove existing namespaces -->\n <xsl:template match=\"*\">\n <!-- remove element prefix -->\n <xsl:element name=\"{local-name()}\">\n <!-- process attributes -->\n <xsl:for-each select=\"@*\">\n <!-- remove attribute prefix -->\n <xsl:attribute name=\"{local-name()}\">\n <xsl:value-of select=\".\"/>\n </xsl:attribute>\n </xsl:for-each>\n <xsl:apply-templates/>\n </xsl:element>\n</xsl:template>\n</xsl:stylesheet>`;\n\n// Function to extend elements with a specific tag name by adding an extension suffix\nexport function extendElementName(xmlFragment: XMLDocument, tagName: string, extension: string) {\n xmlFragment.querySelectorAll(tagName).forEach(element => {\n const newTagName = `${tagName}-${extension}`;\n const newElement = createElementWithNewTagName(element, newTagName);\n element.replaceWith(newElement);\n });\n}\n\n// Function to extend any element with a specific class pattern (e.g., \"extend:suffix\")\nexport function extendElementsWithClass(xmlFragment: XMLDocument, classNamePattern: string) {\n xmlFragment.querySelectorAll('*').forEach(element => {\n const classList = element.classList;\n if (classList) {\n classList.forEach(className => {\n if (className.startsWith(`${classNamePattern}:`)) {\n const suffix = className.slice(`${classNamePattern}:`.length);\n const newTagName = `${element.nodeName}-${suffix}`;\n const newElement = createElementWithNewTagName(element, newTagName);\n element.replaceWith(newElement);\n }\n });\n }\n });\n}\n\n// Helper function to create a new element with a new tag name and copy attributes and children\nfunction createElementWithNewTagName(element, newTagName) {\n const newElement = document.createElement(newTagName);\n // Copy attributes\n for (const attr of element.attributes) {\n newElement.setAttribute(attr.name, attr.value);\n }\n // Copy child nodes\n while (element.firstChild) {\n newElement.appendChild(element.firstChild);\n }\n return newElement;\n}\n\nexport function itemsFromTest(xmlFragment: DocumentFragment) {\n const items: { identifier: string; href: string; category: string }[] = [];\n xmlFragment.querySelectorAll('qti-assessment-item-ref').forEach(el => {\n const identifier = el.getAttribute('identifier');\n const href = el.getAttribute('href');\n const category = el.getAttribute('category');\n items.push({ identifier, href, category });\n });\n return items;\n}\n\nlet currentRequest: XMLHttpRequest | null = null;\n\nexport function loadXML(url, cancelPreviousRequest = false) {\n if (cancelPreviousRequest && currentRequest !== null) {\n currentRequest.abort(); // Abort the ongoing request if there is one\n }\n\n return new Promise<XMLDocument | null>((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n currentRequest = xhr; // Store the current request\n\n xhr.open('GET', url, true);\n xhr.responseType = 'document';\n\n xhr.onload = () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n resolve(xhr.responseXML);\n } else {\n reject(xhr.statusText);\n }\n };\n\n xhr.onerror = () => {\n reject(xhr.statusText);\n };\n\n xhr.send();\n });\n}\n\nexport function parseXML(xmlDocument: string) {\n const parser = new DOMParser();\n const xmlFragment = parser.parseFromString(xmlDocument, 'text/xml');\n return xmlFragment;\n}\n\nexport function toHTML(xmlFragment: Document): DocumentFragment {\n const processor = new XSLTProcessor();\n const xsltDocument = new DOMParser().parseFromString(xmlToHTML, 'text/xml');\n processor.importStylesheet(xsltDocument);\n const itemHTMLFragment = processor.transformToFragment(xmlFragment, document);\n return itemHTMLFragment;\n}\n\nexport function setLocation(xmlFragment: DocumentFragment, location: string) {\n if (!location.endsWith('/')) {\n location += '/';\n }\n\n xmlFragment.querySelectorAll('[src],[href],[primary-path]').forEach(elWithSrc => {\n let attr: 'src' | 'href' | 'primary-path' | '' = '';\n\n if (elWithSrc.getAttribute('src')) {\n attr = 'src';\n }\n if (elWithSrc.getAttribute('href')) {\n attr = 'href';\n }\n if (elWithSrc.getAttribute('primary-path')) {\n attr = 'primary-path';\n }\n const attrValue = elWithSrc.getAttribute(attr)?.trim();\n\n if (!attrValue.startsWith('data:') && !attrValue.startsWith('http')) {\n const newSrcValue = location + encodeURI(attrValue);\n elWithSrc.setAttribute(attr, newSrcValue);\n }\n });\n}\n\nexport function convertCDATAtoComment(xmlFragment: DocumentFragment) {\n const cdataElements = xmlFragment.querySelectorAll('qti-custom-operator[class=\"js.org\"] > qti-base-value');\n cdataElements.forEach(element => {\n const commentText = document.createComment(element.textContent);\n element.replaceChild(commentText, element.firstChild);\n });\n}\n\nexport function stripStyleSheets(xmlFragment: DocumentFragment) {\n // remove qti-stylesheet tag\n xmlFragment.querySelectorAll('qti-stylesheet').forEach(stylesheet => stylesheet.remove());\n}\n","/**\n * Browser based QTI-XML to HTML transformer.\n * Returns an object with methods to load, parse, transform and serialize QTI XML items.\n * @returns An object with methods to load, parse, transform and serialize QTI XML items.\n * @example\n * const qtiTransformer = qtiTransformItem();\n * await qtiTransformer.load('path/to/xml/file.xml');\n * qtiTransformer.path('/assessmentItem/itemBody');\n * const html = qtiTransformer.html();\n * const xml = qtiTransformer.xml();\n * const htmldoc = qtiTransformer.htmldoc();\n * const xmldoc = qtiTransformer.xmldoc();\n *\n * qtiTransformItem().parse(storyXML).html()\n */\n\nimport {\n convertCDATAtoComment,\n extendElementName,\n extendElementsWithClass,\n loadXML,\n parseXML,\n setLocation,\n stripStyleSheets,\n toHTML\n} from './qti-transformers';\n\nexport type transformItemApi = {\n load: (uri: string, cancelPreviousRequest?: boolean) => Promise<transformItemApi>;\n parse: (xmlString: string) => transformItemApi;\n path: (location: string) => transformItemApi;\n fn: (fn: (xmlFragment: XMLDocument) => void) => transformItemApi;\n pciHooks: (uri: string) => transformItemApi;\n extendElementName: (elementName: string, extend: string) => transformItemApi;\n extendElementsWithClass: (param?: string) => transformItemApi;\n customInteraction: (baseRef: string, baseItem: string) => transformItemApi;\n convertCDATAtoComment: () => transformItemApi;\n stripStyleSheets: () => transformItemApi;\n html: () => string;\n xml: () => string;\n htmlDoc: () => DocumentFragment;\n xmlDoc: () => XMLDocument;\n};\n\nexport const qtiTransformItem = () => {\n let xmlFragment: XMLDocument;\n\n const api: transformItemApi = {\n async load(uri: string, cancelPreviousRequest = false): Promise<typeof api> {\n return new Promise<typeof api>(resolve => {\n loadXML(uri, cancelPreviousRequest).then(xml => {\n xmlFragment = xml;\n // set the base path for images and other resources,\n // you probably want to set the base path to the document root else you can use the path method to set it\n api.path(uri.substring(0, uri.lastIndexOf('/')));\n return resolve(api);\n });\n });\n },\n parse(xmlString: string): typeof api {\n xmlFragment = parseXML(xmlString);\n return api;\n },\n path: (location: string): typeof api => {\n setLocation(xmlFragment, location);\n return api;\n },\n fn(fn: (xmlFragment: XMLDocument) => void): typeof api {\n fn(xmlFragment);\n return api;\n },\n pciHooks(uri: string): typeof api {\n const attributes = ['hook', 'module'];\n const documentPath = uri.substring(0, uri.lastIndexOf('/'));\n for (const attribute of attributes) {\n const srcAttributes = xmlFragment.querySelectorAll('[' + attribute + ']');\n srcAttributes.forEach(node => {\n const srcValue = node.getAttribute(attribute)!;\n if (!srcValue.startsWith('data:') && !srcValue.startsWith('http')) {\n // Just paste the relative path of the src location after the documentrootPath\n // old pcis can have a .js, new pci's don't\n node.setAttribute('base-url', uri);\n node.setAttribute(\n 'module',\n documentPath + '/' + encodeURI(srcValue + (srcValue.endsWith('.js') ? '' : '.js'))\n );\n }\n });\n }\n return api;\n },\n extendElementName: (tagName: string, extension: string): typeof api => {\n extendElementName(xmlFragment, tagName, extension);\n return api;\n },\n extendElementsWithClass: (param: string = 'extend'): typeof api => {\n extendElementsWithClass(xmlFragment, param);\n return api;\n },\n customInteraction(baseRef: string, baseItem: string): typeof api {\n const qtiCustomInteraction = xmlFragment.querySelector('qti-custom-interaction');\n const qtiCustomInteractionObject = qtiCustomInteraction.querySelector('object');\n\n qtiCustomInteraction.setAttribute('data-base-ref', baseRef);\n qtiCustomInteraction.setAttribute('data-base-item', baseRef + baseItem);\n qtiCustomInteraction.setAttribute('data', qtiCustomInteractionObject.getAttribute('data'));\n qtiCustomInteraction.setAttribute('width', qtiCustomInteractionObject.getAttribute('width'));\n qtiCustomInteraction.setAttribute('height', qtiCustomInteractionObject.getAttribute('height'));\n\n qtiCustomInteraction.removeChild(qtiCustomInteractionObject);\n return api;\n },\n convertCDATAtoComment(): typeof api {\n convertCDATAtoComment(xmlFragment);\n return api;\n },\n stripStyleSheets(): typeof api {\n stripStyleSheets(xmlFragment);\n return api;\n },\n html() {\n return new XMLSerializer().serializeToString(toHTML(xmlFragment));\n },\n xml(): string {\n return new XMLSerializer().serializeToString(xmlFragment);\n },\n htmlDoc() {\n return toHTML(xmlFragment);\n },\n xmlDoc(): XMLDocument {\n return xmlFragment; // new XMLSerializer().serializeToString(xmlFragment);\n }\n };\n return api;\n};\n","import { loadXML, parseXML } from './qti-transformers';\n\nexport const qtiTransformManifest = (): {\n load: (uri: string) => Promise<typeof api>;\n assessmentTest: () => { href: string; identifier: string };\n} => {\n let xmlFragment: XMLDocument;\n\n const api = {\n async load(uri) {\n return new Promise<typeof api>(resolve => {\n loadXML(uri).then(xml => {\n xmlFragment = xml;\n return resolve(api);\n });\n });\n },\n parse(xmlString: string) {\n xmlFragment = parseXML(xmlString);\n },\n assessmentTest() {\n const el = xmlFragment.querySelector('resource[type=\"imsqti_test_xmlv3p0\"]');\n return { href: el.getAttribute('href'), identifier: el.getAttribute('identifier') };\n }\n };\n return api;\n};\n","/**\n * Returns an object with methods to load, parse and transform QTI tests.\n * @returns An object with methods to load, parse and transform QTI tests.\n * @example\n * const qtiTransformer = qtiTransformTest();\n * await qtiTransformer.load('https://example.com/test.xml');\n * const items = qtiTransformer.items();\n * const html = qtiTransformer.html();\n * const xml = qtiTransformer.xml();\n */\n\nimport { itemsFromTest, loadXML, parseXML, toHTML } from './qti-transformers';\n\nexport type transformTestApi = {\n load: (uri: string) => Promise<transformTestApi>;\n parse: (xmlString: string) => transformTestApi;\n fn: (fn: (xmlFragment: XMLDocument) => void) => transformTestApi;\n items: () => { identifier: string; href: string; category: string }[];\n html: () => string;\n xml: () => string;\n htmlDoc: () => DocumentFragment;\n xmlDoc: () => XMLDocument;\n};\n\nexport const qtiTransformTest = (): transformTestApi => {\n let xmlFragment: XMLDocument;\n\n const api: transformTestApi = {\n async load(uri) {\n return new Promise<transformTestApi>((resolve, _) => {\n loadXML(uri).then(xml => {\n xmlFragment = xml;\n return resolve(api);\n });\n });\n },\n parse(xmlString: string) {\n xmlFragment = parseXML(xmlString);\n return api;\n },\n fn(fn: (xmlFragment: XMLDocument) => void) {\n fn(xmlFragment);\n return api;\n },\n items() {\n return itemsFromTest(xmlFragment);\n },\n html() {\n return new XMLSerializer().serializeToString(toHTML(xmlFragment));\n },\n xml(): string {\n return new XMLSerializer().serializeToString(xmlFragment);\n },\n htmlDoc() {\n return toHTML(xmlFragment);\n },\n xmlDoc(): XMLDocument {\n return xmlFragment;\n }\n };\n return api;\n};\n","import { QtiAssessmentItem } from '../qti-components';\nimport { qtiTransformItem, qtiTransformTest } from '../qti-transformers';\nimport { qtiTransformManifest } from '../qti-transformers/qti-transform-manifest';\n\nexport type ManifestInfo = {\n testIdentifier: string;\n testHTMLDoc: DocumentFragment;\n testURI: string;\n testURL: string;\n items: {\n identifier: string;\n href: string;\n category: string;\n }[];\n};\n\n// Utility function to ensure package URIs end with a '/'\n// const normalizeUri = (uri: string) => (uri.endsWith('/') ? uri : `${uri}/`);\n\n// Fetches assessment data from the manifest\nexport const getManifestInfo = async (manifestURL: string): Promise<ManifestInfo> => {\n const baseURI = manifestURL.substring(0, manifestURL.lastIndexOf('/'));\n\n const test = await qtiTransformManifest()\n .load(`${manifestURL}`)\n .then(api => api.assessmentTest());\n\n const testHTMLDoc = await qtiTransformTest()\n .load(`${baseURI}/${test.href}`)\n .then(api => api.htmlDoc());\n\n const items = await qtiTransformTest()\n .load(`${baseURI}/${test.href}`)\n .then(api => api.items());\n\n const testURL = `${baseURI}/${test.href}`;\n const testURI = `${baseURI}/${test.href.substring(0, test.href.lastIndexOf('/'))}`;\n\n return {\n testHTMLDoc,\n testURI,\n testURL,\n items,\n testIdentifier: test.identifier\n };\n};\n\n// Fetches a single item by URI\nexport const getItemByUri = async (itemUri: string): Promise<QtiAssessmentItem> =>\n qtiTransformItem()\n .load(itemUri)\n .then(api => api.htmlDoc().firstElementChild as QtiAssessmentItem);\n"],"mappings":"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","names":["xml","xml","xml"]}
1
+ {"version":3,"sources":["../../src/lib/qti-transformers/qti-transformers.ts","../../src/lib/qti-transformers/qti-transform-item.ts","../../src/lib/qti-transformers/qti-transform-manifest.ts","../../src/lib/qti-transformers/qti-transform-test.ts","../../src/lib/qti-loader/qti-loader.ts"],"sourcesContent":["const xml = String.raw;\n\n/* <!-- convert CDATA to comments -->\n <xsl:template match=\"text()[contains(., 'CDATA')]\">\n <xsl:comment>\n <xsl:value-of select=\".\"/>\n </xsl:comment>\n</xsl:template>\n*/\n\n/*\n <!-- remove xml comments -->\n <xsl:template match=\"comment()\" />\n */\n\nconst xmlToHTML = xml`<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">\n<xsl:output method=\"html\" version=\"5.0\" encoding=\"UTF-8\" indent=\"yes\" />\n <xsl:template match=\"@*|node()\">\n <xsl:copy>\n <xsl:apply-templates select=\"@*|node()\"/>\n </xsl:copy>\n </xsl:template>\n\n <!-- remove existing namespaces -->\n <xsl:template match=\"*\">\n <!-- remove element prefix -->\n <xsl:element name=\"{local-name()}\">\n <!-- process attributes -->\n <xsl:for-each select=\"@*\">\n <!-- remove attribute prefix -->\n <xsl:attribute name=\"{local-name()}\">\n <xsl:value-of select=\".\"/>\n </xsl:attribute>\n </xsl:for-each>\n <xsl:apply-templates/>\n </xsl:element>\n</xsl:template>\n</xsl:stylesheet>`;\n\n// Function to extend elements with a specific tag name by adding an extension suffix\nexport function extendElementName(xmlFragment: XMLDocument, tagName: string, extension: string) {\n xmlFragment.querySelectorAll(tagName).forEach(element => {\n const newTagName = `${tagName}-${extension}`;\n const newElement = createElementWithNewTagName(element, newTagName);\n element.replaceWith(newElement);\n });\n}\n\n// Function to extend any element with a specific class pattern (e.g., \"extend:suffix\")\nexport function extendElementsWithClass(xmlFragment: XMLDocument, classNamePattern: string) {\n xmlFragment.querySelectorAll('*').forEach(element => {\n const classList = element.classList;\n if (classList) {\n classList.forEach(className => {\n if (className.startsWith(`${classNamePattern}:`)) {\n const suffix = className.slice(`${classNamePattern}:`.length);\n const newTagName = `${element.nodeName}-${suffix}`;\n const newElement = createElementWithNewTagName(element, newTagName);\n element.replaceWith(newElement);\n }\n });\n }\n });\n}\n\n// Helper function to create a new element with a new tag name and copy attributes and children\nfunction createElementWithNewTagName(element, newTagName) {\n const newElement = document.createElement(newTagName);\n // Copy attributes\n for (const attr of element.attributes) {\n newElement.setAttribute(attr.name, attr.value);\n }\n // Copy child nodes\n while (element.firstChild) {\n newElement.appendChild(element.firstChild);\n }\n return newElement;\n}\n\nexport function itemsFromTest(xmlFragment: DocumentFragment) {\n const items: { identifier: string; href: string; category: string }[] = [];\n xmlFragment.querySelectorAll('qti-assessment-item-ref').forEach(el => {\n const identifier = el.getAttribute('identifier');\n const href = el.getAttribute('href');\n const category = el.getAttribute('category');\n items.push({ identifier, href, category });\n });\n return items;\n}\n\nlet currentRequest: XMLHttpRequest | null = null;\n\nexport function loadXML(url, cancelPreviousRequest = false) {\n if (cancelPreviousRequest && currentRequest !== null) {\n currentRequest.abort(); // Abort the ongoing request if there is one\n }\n\n return new Promise<XMLDocument | null>((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n currentRequest = xhr; // Store the current request\n\n xhr.open('GET', url, true);\n xhr.responseType = 'document';\n\n xhr.onload = () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n resolve(xhr.responseXML);\n } else {\n reject(xhr.statusText);\n }\n };\n\n xhr.onerror = () => {\n reject(xhr.statusText);\n };\n\n xhr.send();\n });\n}\n\nexport function parseXML(xmlDocument: string) {\n const parser = new DOMParser();\n const xmlFragment = parser.parseFromString(xmlDocument, 'text/xml');\n return xmlFragment;\n}\n\nexport function toHTML(xmlFragment: Document): DocumentFragment {\n const processor = new XSLTProcessor();\n const xsltDocument = new DOMParser().parseFromString(xmlToHTML, 'text/xml');\n processor.importStylesheet(xsltDocument);\n const itemHTMLFragment = processor.transformToFragment(xmlFragment, document);\n return itemHTMLFragment;\n}\n\nexport function setLocation(xmlFragment: DocumentFragment, location: string) {\n if (!location.endsWith('/')) {\n location += '/';\n }\n\n xmlFragment.querySelectorAll('[src],[href],[primary-path]').forEach(elWithSrc => {\n let attr: 'src' | 'href' | 'primary-path' | '' = '';\n\n if (elWithSrc.getAttribute('src')) {\n attr = 'src';\n }\n if (elWithSrc.getAttribute('href')) {\n attr = 'href';\n }\n if (elWithSrc.getAttribute('primary-path')) {\n attr = 'primary-path';\n }\n const attrValue = elWithSrc.getAttribute(attr)?.trim();\n\n if (!attrValue.startsWith('data:') && !attrValue.startsWith('http')) {\n const newSrcValue = location + encodeURI(attrValue);\n elWithSrc.setAttribute(attr, newSrcValue);\n }\n });\n}\n\nexport function convertCDATAtoComment(xmlFragment: DocumentFragment) {\n const cdataElements = xmlFragment.querySelectorAll('qti-custom-operator[class=\"js.org\"] > qti-base-value');\n cdataElements.forEach(element => {\n const commentText = document.createComment(element.textContent);\n element.replaceChild(commentText, element.firstChild);\n });\n}\n\nexport function stripStyleSheets(xmlFragment: DocumentFragment) {\n // remove qti-stylesheet tag\n xmlFragment.querySelectorAll('qti-stylesheet').forEach(stylesheet => stylesheet.remove());\n}\n","/**\n * Browser based QTI-XML to HTML transformer.\n * Returns an object with methods to load, parse, transform and serialize QTI XML items.\n * @returns An object with methods to load, parse, transform and serialize QTI XML items.\n * @example\n * const qtiTransformer = qtiTransformItem();\n * await qtiTransformer.load('path/to/xml/file.xml');\n * qtiTransformer.path('/assessmentItem/itemBody');\n * const html = qtiTransformer.html();\n * const xml = qtiTransformer.xml();\n * const htmldoc = qtiTransformer.htmldoc();\n * const xmldoc = qtiTransformer.xmldoc();\n *\n * qtiTransformItem().parse(storyXML).html()\n */\n\nimport {\n convertCDATAtoComment,\n extendElementName,\n extendElementsWithClass,\n loadXML,\n parseXML,\n setLocation,\n stripStyleSheets,\n toHTML\n} from './qti-transformers';\n\nexport type transformItemApi = {\n load: (uri: string, cancelPreviousRequest?: boolean) => Promise<transformItemApi>;\n parse: (xmlString: string) => transformItemApi;\n path: (location: string) => transformItemApi;\n fn: (fn: (xmlFragment: XMLDocument) => void) => transformItemApi;\n pciHooks: (uri: string) => transformItemApi;\n extendElementName: (elementName: string, extend: string) => transformItemApi;\n extendElementsWithClass: (param?: string) => transformItemApi;\n customInteraction: (baseRef: string, baseItem: string) => transformItemApi;\n convertCDATAtoComment: () => transformItemApi;\n stripStyleSheets: () => transformItemApi;\n html: () => string;\n xml: () => string;\n htmlDoc: () => DocumentFragment;\n xmlDoc: () => XMLDocument;\n};\n\nexport const qtiTransformItem = () => {\n let xmlFragment: XMLDocument;\n\n const api: transformItemApi = {\n async load(uri: string, cancelPreviousRequest = false): Promise<typeof api> {\n return new Promise<typeof api>(resolve => {\n loadXML(uri, cancelPreviousRequest).then(xml => {\n xmlFragment = xml;\n // set the base path for images and other resources,\n // you probably want to set the base path to the document root else you can use the path method to set it\n api.path(uri.substring(0, uri.lastIndexOf('/')));\n return resolve(api);\n });\n });\n },\n parse(xmlString: string): typeof api {\n xmlFragment = parseXML(xmlString);\n return api;\n },\n path: (location: string): typeof api => {\n setLocation(xmlFragment, location);\n return api;\n },\n fn(fn: (xmlFragment: XMLDocument) => void): typeof api {\n fn(xmlFragment);\n return api;\n },\n pciHooks(uri: string): typeof api {\n const attributes = ['hook', 'module'];\n const documentPath = uri.substring(0, uri.lastIndexOf('/'));\n for (const attribute of attributes) {\n const srcAttributes = xmlFragment.querySelectorAll('[' + attribute + ']');\n srcAttributes.forEach(node => {\n const srcValue = node.getAttribute(attribute)!;\n if (!srcValue.startsWith('data:') && !srcValue.startsWith('http')) {\n // Just paste the relative path of the src location after the documentrootPath\n // old pcis can have a .js, new pci's don't\n node.setAttribute('base-url', uri);\n node.setAttribute(\n 'module',\n documentPath + '/' + encodeURI(srcValue + (srcValue.endsWith('.js') ? '' : '.js'))\n );\n }\n });\n }\n return api;\n },\n extendElementName: (tagName: string, extension: string): typeof api => {\n extendElementName(xmlFragment, tagName, extension);\n return api;\n },\n extendElementsWithClass: (param: string = 'extend'): typeof api => {\n extendElementsWithClass(xmlFragment, param);\n return api;\n },\n customInteraction(baseRef: string, baseItem: string): typeof api {\n const qtiCustomInteraction = xmlFragment.querySelector('qti-custom-interaction');\n const qtiCustomInteractionObject = qtiCustomInteraction.querySelector('object');\n\n qtiCustomInteraction.setAttribute('data-base-ref', baseRef);\n qtiCustomInteraction.setAttribute('data-base-item', baseRef + baseItem);\n qtiCustomInteraction.setAttribute('data', qtiCustomInteractionObject.getAttribute('data'));\n qtiCustomInteraction.setAttribute('width', qtiCustomInteractionObject.getAttribute('width'));\n qtiCustomInteraction.setAttribute('height', qtiCustomInteractionObject.getAttribute('height'));\n\n qtiCustomInteraction.removeChild(qtiCustomInteractionObject);\n return api;\n },\n convertCDATAtoComment(): typeof api {\n convertCDATAtoComment(xmlFragment);\n return api;\n },\n stripStyleSheets(): typeof api {\n stripStyleSheets(xmlFragment);\n return api;\n },\n html() {\n return new XMLSerializer().serializeToString(toHTML(xmlFragment));\n },\n xml(): string {\n return new XMLSerializer().serializeToString(xmlFragment);\n },\n htmlDoc() {\n return toHTML(xmlFragment);\n },\n xmlDoc(): XMLDocument {\n return xmlFragment; // new XMLSerializer().serializeToString(xmlFragment);\n }\n };\n return api;\n};\n","import { loadXML, parseXML } from './qti-transformers';\n\nexport const qtiTransformManifest = (): {\n load: (uri: string) => Promise<typeof api>;\n assessmentTest: () => { href: string; identifier: string };\n} => {\n let xmlFragment: XMLDocument;\n\n const api = {\n async load(uri) {\n return new Promise<typeof api>(resolve => {\n loadXML(uri).then(xml => {\n xmlFragment = xml;\n return resolve(api);\n });\n });\n },\n parse(xmlString: string) {\n xmlFragment = parseXML(xmlString);\n },\n assessmentTest() {\n const el = xmlFragment.querySelector('resource[type=\"imsqti_test_xmlv3p0\"]');\n return { href: el.getAttribute('href'), identifier: el.getAttribute('identifier') };\n }\n };\n return api;\n};\n","/**\n * Returns an object with methods to load, parse and transform QTI tests.\n * @returns An object with methods to load, parse and transform QTI tests.\n * @example\n * const qtiTransformer = qtiTransformTest();\n * await qtiTransformer.load('https://example.com/test.xml');\n * const items = qtiTransformer.items();\n * const html = qtiTransformer.html();\n * const xml = qtiTransformer.xml();\n */\n\nimport { itemsFromTest, loadXML, parseXML, setLocation, toHTML } from './qti-transformers';\n\nexport type transformTestApi = {\n load: (uri: string) => Promise<transformTestApi>;\n parse: (xmlString: string) => transformTestApi;\n path: (location: string) => transformTestApi;\n fn: (fn: (xmlFragment: XMLDocument) => void) => transformTestApi;\n items: () => { identifier: string; href: string; category: string }[];\n html: () => string;\n xml: () => string;\n htmlDoc: () => DocumentFragment;\n xmlDoc: () => XMLDocument;\n};\n\nexport const qtiTransformTest = (): transformTestApi => {\n let xmlFragment: XMLDocument;\n\n const api: transformTestApi = {\n async load(uri) {\n return new Promise<transformTestApi>((resolve, _) => {\n loadXML(uri).then(xml => {\n xmlFragment = xml;\n\n api.path(uri.substring(0, uri.lastIndexOf('/')));\n return resolve(api);\n });\n });\n },\n parse(xmlString: string) {\n xmlFragment = parseXML(xmlString);\n return api;\n },\n path: (location: string): typeof api => {\n setLocation(xmlFragment, location);\n return api;\n },\n fn(fn: (xmlFragment: XMLDocument) => void) {\n fn(xmlFragment);\n return api;\n },\n items() {\n return itemsFromTest(xmlFragment);\n },\n html() {\n return new XMLSerializer().serializeToString(toHTML(xmlFragment));\n },\n xml(): string {\n return new XMLSerializer().serializeToString(xmlFragment);\n },\n htmlDoc() {\n return toHTML(xmlFragment);\n },\n xmlDoc(): XMLDocument {\n return xmlFragment;\n }\n };\n return api;\n};\n","import { QtiAssessmentItem } from '../qti-components';\nimport { qtiTransformItem, qtiTransformTest } from '../qti-transformers';\nimport { qtiTransformManifest } from '../qti-transformers/qti-transform-manifest';\n\nexport type ManifestInfo = {\n testIdentifier: string;\n testHTMLDoc: DocumentFragment;\n testURI: string;\n testURL: string;\n items: {\n identifier: string;\n href: string;\n category: string;\n }[];\n};\n\n// Utility function to ensure package URIs end with a '/'\n// const normalizeUri = (uri: string) => (uri.endsWith('/') ? uri : `${uri}/`);\n\n// Fetches assessment data from the manifest\nexport const getManifestInfo = async (manifestURL: string): Promise<ManifestInfo> => {\n const baseURI = manifestURL.substring(0, manifestURL.lastIndexOf('/'));\n\n const test = await qtiTransformManifest()\n .load(`${manifestURL}`)\n .then(api => api.assessmentTest());\n\n const testHTMLDoc = await qtiTransformTest()\n .load(`${baseURI}/${test.href}`)\n .then(api => api.htmlDoc());\n\n const items = await qtiTransformTest()\n .load(`${baseURI}/${test.href}`)\n .then(api => api.items());\n\n const testURL = `${baseURI}/${test.href}`;\n const testURI = `${baseURI}/${test.href.substring(0, test.href.lastIndexOf('/'))}`;\n\n return {\n testHTMLDoc,\n testURI,\n testURL,\n items,\n testIdentifier: test.identifier\n };\n};\n\n// Fetches a single item by URI\nexport const getItemByUri = async (itemUri: string): Promise<QtiAssessmentItem> =>\n qtiTransformItem()\n .load(itemUri)\n .then(api => api.htmlDoc().firstElementChild as QtiAssessmentItem);\n"],"mappings":"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","names":["xml","xml","xml"]}
@@ -501,6 +501,23 @@ export type QtiChoiceInteractionProps = {
501
501
  "onqti-interaction-response"?: (e: CustomEvent<CustomEvent>) => void;
502
502
  };
503
503
 
504
+ export type QtiUploadInteractionProps = {
505
+ /** */
506
+ "response-identifier"?: string;
507
+ /** */
508
+ disabled?: boolean;
509
+ /** */
510
+ readonly?: boolean;
511
+ /** */
512
+ value?: string | string[];
513
+ /** */
514
+ correctResponse?: string | string[];
515
+ /** */
516
+ "onqti-interaction-response"?: (e: CustomEvent<CustomEvent>) => void;
517
+ /** */
518
+ "onqti-register-interaction"?: (e: CustomEvent<CustomEvent>) => void;
519
+ };
520
+
504
521
  export type QtiOutcomeProcessingProps = {};
505
522
 
506
523
  export type QtiPortableCustomInteractionProps = {
@@ -563,10 +580,6 @@ export type QtiAssociateInteractionProps = {
563
580
  /** */
564
581
  readonly?: boolean;
565
582
  /** */
566
- dragDropApi?: TouchDragAndDrop;
567
- /** */
568
- configuration?: InteractionConfiguration;
569
- /** */
570
583
  value?: string | string[];
571
584
  /** */
572
585
  correctResponse?: string | string[];
@@ -644,10 +657,6 @@ export type QtiGapMatchInteractionProps = {
644
657
  /** */
645
658
  correctResponse?: string | string[];
646
659
  /** */
647
- dragDropApi?: TouchDragAndDrop;
648
- /** */
649
- configuration?: InteractionConfiguration;
650
- /** */
651
660
  value?: string | string[];
652
661
  /** */
653
662
  "onqti-register-interaction"?: (e: CustomEvent<CustomEvent>) => void;
@@ -721,10 +730,6 @@ export type QtiGraphicGapMatchInteractionProps = {
721
730
  /** */
722
731
  readonly?: boolean;
723
732
  /** */
724
- dragDropApi?: TouchDragAndDrop;
725
- /** */
726
- configuration?: InteractionConfiguration;
727
- /** */
728
733
  value?: string | string[];
729
734
  /** */
730
735
  correctResponse?: string | string[];
@@ -779,6 +784,8 @@ export type QtiHotspotInteractionProps = {
779
784
  };
780
785
 
781
786
  export type QtiMatchInteractionProps = {
787
+ /** */
788
+ class?: string;
782
789
  /** */
783
790
  "response-identifier"?: string;
784
791
  /** */
@@ -790,28 +797,10 @@ export type QtiMatchInteractionProps = {
790
797
  /** */
791
798
  readonly?: boolean;
792
799
  /** */
793
- rows?: QtiSimpleAssociableChoice[];
794
- /** */
795
- cols?: QtiSimpleAssociableChoice[];
796
- /** */
797
- lastCheckedRadio?: HTMLInputElement | null;
798
- /** */
799
- _response?: string | string[];
800
- /** */
801
800
  value?: string | string[];
802
801
  /** */
803
- correctOptions?: string[];
804
- /** */
805
- handleRadioClick?: string;
806
- /** */
807
- handleRadioChange?: string;
808
- /** */
809
802
  correctResponse?: string | string[];
810
803
  /** */
811
- dragDropApi?: TouchDragAndDrop;
812
- /** */
813
- configuration?: InteractionConfiguration;
814
- /** */
815
804
  "onqti-register-interaction"?: (e: CustomEvent<CustomEvent>) => void;
816
805
  /** */
817
806
  "onqti-interaction-response"?: (e: CustomEvent<CustomEvent>) => void;
@@ -860,10 +849,6 @@ export type QtiOrderInteractionProps = {
860
849
  /** */
861
850
  correctResponse?: string | string[];
862
851
  /** */
863
- dragDropApi?: TouchDragAndDrop;
864
- /** */
865
- configuration?: InteractionConfiguration;
866
- /** */
867
852
  value?: string | string[];
868
853
  /** */
869
854
  "onqti-register-interaction"?: (e: CustomEvent<CustomEvent>) => void;
@@ -906,10 +891,6 @@ export type QtiSelectPointInteractionProps = {
906
891
  };
907
892
 
908
893
  export type QtiSliderInteractionProps = {
909
- /** */
910
- "step-label"?: boolean;
911
- /** */
912
- reverse?: boolean;
913
894
  /** */
914
895
  "lower-bound"?: number;
915
896
  /** */
@@ -917,27 +898,9 @@ export type QtiSliderInteractionProps = {
917
898
  /** */
918
899
  step?: number;
919
900
  /** */
920
- "response-identifier"?: string;
921
- /** */
922
- disabled?: boolean;
923
- /** */
924
- readonly?: boolean;
925
- /** */
926
- csLive?: CSSStyleDeclaration;
927
- /** */
928
- _handleDisabledChange?: string;
929
- /** */
930
- _handleReadonlyChange?: string;
901
+ value?: string;
931
902
  /** */
932
- value?: string | string[];
933
- /** */
934
- response?: string;
935
- /** */
936
- correctResponse?: string | string[];
937
- /** emitted when the interaction wants to register itself */
938
- "onqti-register-interaction"?: (e: CustomEvent<CustomEvent>) => void;
939
- /** emitted when the interaction changes */
940
- "onqti-interaction-response"?: (e: CustomEvent<CustomEvent>) => void;
903
+ onchange?: (e: CustomEvent<Event>) => void;
941
904
  };
942
905
 
943
906
  export type QtiCustomOperatorProps = {
@@ -1135,8 +1098,6 @@ export type QtiTestPartProps = {
1135
1098
  };
1136
1099
 
1137
1100
  export type QtiTestProps = {
1138
- /** the relative location to the QTI assessment.xml file */
1139
- testURL?: string;
1140
1101
  /** */
1141
1102
  context?: TestContext;
1142
1103
  };
@@ -1210,8 +1171,12 @@ export type TestItemLinkProps = {
1210
1171
  };
1211
1172
 
1212
1173
  export type TestContainerProps = {
1213
- /** */
1174
+ /** URL of the item to load */
1214
1175
  "test-url"?: string;
1176
+ /** A parsed HTML document */
1177
+ testDoc?: DocumentFragment;
1178
+ /** The raw XML string */
1179
+ testXML?: string;
1215
1180
  };
1216
1181
 
1217
1182
  export type TestPagingButtonsStampProps = {
@@ -1233,17 +1198,15 @@ export type TestPagingButtonsStampProps = {
1233
1198
  "onqti-request-test-item"?: (e: CustomEvent<CustomEvent>) => void;
1234
1199
  };
1235
1200
 
1236
- export type QtiItemProps = {
1237
- /** */
1238
- identifier?: string | undefined;
1239
- /** */
1240
- href?: string | undefined;
1241
- /** */
1242
- xmlDoc?: DocumentFragment;
1243
- /** */
1244
- assessmentItem?: QtiAssessmentItem | null;
1245
- /** */
1246
- "onqti-item-connected"?: (e: CustomEvent<CustomEvent>) => void;
1201
+ export type QtiItemProps = {};
1202
+
1203
+ export type ItemContainerProps = {
1204
+ /** URL of the item to load */
1205
+ "item-url"?: string;
1206
+ /** A parsed HTML document */
1207
+ itemDoc?: DocumentFragment;
1208
+ /** The raw XML string */
1209
+ itemXML?: string;
1247
1210
  };
1248
1211
 
1249
1212
  export type CustomElements = {
@@ -1697,6 +1660,17 @@ export type CustomElements = {
1697
1660
  */
1698
1661
  "qti-choice-interaction": Partial<QtiChoiceInteractionProps & BaseProps & BaseEvents>;
1699
1662
 
1663
+ /**
1664
+ *
1665
+ * ---
1666
+ *
1667
+ *
1668
+ * ### **Events:**
1669
+ * - **qti-interaction-response**
1670
+ * - **qti-register-interaction**
1671
+ */
1672
+ "qti-upload-interaction": Partial<QtiUploadInteractionProps & BaseProps & BaseEvents>;
1673
+
1700
1674
  /**
1701
1675
  *
1702
1676
  * ---
@@ -1883,30 +1857,12 @@ export type CustomElements = {
1883
1857
  "qti-select-point-interaction": Partial<QtiSelectPointInteractionProps & BaseProps & BaseEvents>;
1884
1858
 
1885
1859
  /**
1886
- * The SliderInteraction.Type (qti-slider-interaction) presents the candidate with a control for selecting a numerical value between a lower and upper bound.
1860
+ *
1887
1861
  * ---
1888
1862
  *
1889
1863
  *
1890
1864
  * ### **Events:**
1891
- * - **qti-register-interaction** - emitted when the interaction wants to register itself
1892
- * - **qti-interaction-response** - emitted when the interaction changes
1893
- *
1894
- * ### **Slots:**
1895
- * - _default_ - The default slot where <qti-simple-choice> must be placed.
1896
- * - **prompt** - slot where the prompt is placed.
1897
- *
1898
- * ### **CSS Properties:**
1899
- * - **--show-value** - shows the current value while sliding _(default: undefined)_
1900
- * - **--show-ticks** - shows the ticks according to steps _(default: undefined)_
1901
- * - **--show-bounds** - shows value for lower and upper boundary _(default: undefined)_
1902
- *
1903
- * ### **CSS Parts:**
1904
- * - **slider** - -- slider inluding, bounds and ticks and value, use it for paddings and margins
1905
- * - **bounds** - -- div for bounds, containing two divs for with min, and max bounds value
1906
- * - **ticks** - -- div for ticks, use lineair gradient and exposed css variables for styling
1907
- * - **rail** - -- div for rail, style according to needs
1908
- * - **knob** - -- div, should be relative or absolute
1909
- * - **value** - -- div, containing value
1865
+ * - **change**
1910
1866
  */
1911
1867
  "qti-slider-interaction": Partial<QtiSliderInteractionProps & BaseProps & BaseEvents>;
1912
1868
 
@@ -2064,30 +2020,47 @@ export type CustomElements = {
2064
2020
  *
2065
2021
  * ### Example Usage
2066
2022
  *
2067
- * Minimal markup:
2068
- * ```html
2069
- * <qti-test test="./path/to/assessment.xml">
2070
- * <test-container></test-container>
2071
- * </qti-test>
2072
- * ```
2023
+ * Minimal example including navigation:
2073
2024
  *
2074
- * With navigation buttons:
2075
2025
  * ```html
2076
- * <qti-test >
2026
+ * <qti-test>
2077
2027
  * <test-container test-url="./path/to/assessment.xml"></test-container>
2078
- * <div class="flex">
2028
+ * <nav class="flex">
2079
2029
  * <test-prev></test-prev>
2080
2030
  * <test-next></test-next>
2081
- * </div>
2031
+ * </nav>
2082
2032
  * </qti-test>
2083
2033
  * ```
2084
2034
  *
2035
+ * Use the following file structure
2036
+ * A qti-test loads a QTI3.0 assessmenttest.xml file from a package folder.
2037
+ *
2038
+ * ```plaintext
2039
+ * Root/
2040
+ * ├── index.html
2041
+ * └── /assets/api/examples/
2042
+ * ├── assessmenttest.xml
2043
+ * └── imsmanifest.xml
2044
+ *
2045
+ * ```
2046
+ *
2047
+ * ### Test components
2048
+ *
2049
+ * Use test components inside the qti-test component for added functionality.
2050
+ * ### Test next
2051
+ * `<test-next> | TestNext`
2052
+ *
2053
+ * ### Test prev
2054
+ *
2055
+ * `<test-prev> | TestPrev`
2056
+ * ### Test components
2057
+ *
2085
2058
  * You can use normal class names to style the elements.
2086
2059
  * And you can use the `test-prev` and `test-next` elements to navigate through the test.
2087
2060
  * ---
2088
2061
  *
2089
2062
  */
2090
- "qti-player": Partial<QtiTestProps & BaseProps & BaseEvents>;
2063
+ "qti-test": Partial<QtiTestProps & BaseProps & BaseEvents>;
2091
2064
 
2092
2065
  /**
2093
2066
  * Represents a custom element for navigating to the next test item.
@@ -2134,16 +2107,16 @@ export type CustomElements = {
2134
2107
  "test-item-link": Partial<TestItemLinkProps & BaseProps & BaseEvents>;
2135
2108
 
2136
2109
  /**
2137
- * `<test-container>` is a custom element designed for hosting the qti-assessment-test.
2110
+ * `<test-container>` is a custom element designed for hosting the qti-assessment-item.
2138
2111
  * The `qti-assessment-test` will be placed inside the shadow DOM of this element.
2112
+ * The element loads the item from the provided URL and renders it inside the shadow DOM.
2139
2113
  *
2140
- * ### Example Usage
2141
- * The `test-container` element to hosts the visual representation of the items.
2142
- * You can style the container by adding a class to the element.
2114
+ * ### Styling
2115
+ * Add a class to the element for styling.
2143
2116
  *
2144
2117
  * ```html
2145
- * <qti-test testurl="./path/to/assessment.xml">
2146
- * <test-container class="container bg-white m-2"></test-container>
2118
+ * <qti-test>
2119
+ * <test-container class="m-4 bg-white" test-url="./path/to/item.xml"></test-container>
2147
2120
  * </qti-test>
2148
2121
  * ```
2149
2122
  * ---
@@ -2163,12 +2136,36 @@ export type CustomElements = {
2163
2136
  "test-paging-buttons-stamp": Partial<TestPagingButtonsStampProps & BaseProps & BaseEvents>;
2164
2137
 
2165
2138
  /**
2139
+ * `<qti-item>` is a custom element designed for rendering a single `qti-assessment-item`.
2140
+ * It can also host some functionalities to interact with the item like scoring, showing feedback, etc.
2141
+ * Placing a mandatory `<item-container>` inside '<qti-item>' will load or parse the item and render it.
2142
+ * See `<item-container>` for more details.
2166
2143
  *
2144
+ * ```html
2145
+ * <qti-item>
2146
+ * <item-container class="m-4 bg-white" item-url="./path/to/item.xml"></item-container>
2147
+ * </qti-item>
2148
+ * ```
2167
2149
  * ---
2168
2150
  *
2169
- *
2170
- * ### **Events:**
2171
- * - **qti-item-connected**
2172
2151
  */
2173
2152
  "qti-item": Partial<QtiItemProps & BaseProps & BaseEvents>;
2153
+
2154
+ /**
2155
+ * `<item-container>` is a custom element designed for hosting the qti-assessment-item.
2156
+ * The `qti-assessment-item` will be placed inside the shadow DOM of this element.
2157
+ * The element loads the item from the provided URL and renders it inside the shadow DOM.
2158
+ *
2159
+ * ### Styling
2160
+ * Add a class to the element for styling.
2161
+ *
2162
+ * ```html
2163
+ * <qti-item>
2164
+ * <item-container class="m-4 bg-white" item-url="./path/to/item.xml"></item-container>
2165
+ * </qti-item>
2166
+ * ```
2167
+ * ---
2168
+ *
2169
+ */
2170
+ "item-container": Partial<ItemContainerProps & BaseProps & BaseEvents>;
2174
2171
  };