@matinfo/vitepress-plugin-quiz 0.9.9

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vitepress-plugin-quiz.umd.cjs","sources":["../src/styleManager.ts","../src/md-plugin.ts","../src/locales.ts","../src/utils.ts","../src/QuizQuestion.vue","../src/QuizPage.vue","../src/index.ts"],"sourcesContent":["import quizCssInline from \"./quiz.css?inline\"\n\nlet stylesInjected = false\n\nexport function ensureStylesInjected(): void {\n if (typeof document === \"undefined\") return\n if (stylesInjected) return\n const styleId = \"vitepress-plugin-quiz-styles\"\n if (document.getElementById(styleId)) {\n stylesInjected = true\n return\n }\n const style = document.createElement(\"style\")\n style.id = styleId\n style.textContent = quizCssInline\n document.head.appendChild(style)\n stylesInjected = true\n}\n","import type MarkdownIt from \"markdown-it\"\nimport type StateBlock from \"markdown-it/lib/rules_block/state_block.mjs\"\nimport type { QuizData, QuizAnswer } from \"./types/quiz\"\n\nconst QUIZ_RE = /^:::quiz\\s*$/\nconst CLOSE_RE = /^:::\\s*$/\n\n/**\n * Register the quiz block rule on a markdown-it instance.\n * Use in VitePress config:\n * markdown: { config(md) { md.use(quizMarkdownPlugin) } }\n */\nexport function quizMarkdownPlugin(md: MarkdownIt): void {\n const escapeHtml = md.utils.escapeHtml\n\n md.block.ruler.before(\n \"fence\",\n \"quiz\",\n (state, startLine, endLine, silent) =>\n quizBlockRule(state, startLine, endLine, silent, escapeHtml),\n { alt: [\"paragraph\", \"reference\", \"blockquote\", \"list\"] },\n )\n\n md.renderer.rules.quiz = (tokens, idx) => tokens[idx].content\n\n // Wrap entire token stream with <QuizPage>…</QuizPage> if quiz tokens exist\n md.core.ruler.push(\"quiz_page_wrap\", (state) => {\n const hasQuiz = state.tokens.some((t) => t.type === \"quiz\")\n if (!hasQuiz) return\n\n const open = new state.Token(\"html_block\", \"\", 0)\n open.content = \"<QuizPage>\\n\"\n open.block = true\n\n const close = new state.Token(\"html_block\", \"\", 0)\n close.content = \"</QuizPage>\\n\"\n close.block = true\n\n state.tokens.unshift(open)\n state.tokens.push(close)\n })\n}\n\n/* ── block rule ──────────────────────────────────────────────────────── */\n\nfunction quizBlockRule(\n state: StateBlock,\n startLine: number,\n endLine: number,\n silent: boolean,\n escapeHtml: (s: string) => string,\n): boolean {\n const startPos = state.bMarks[startLine] + state.tShift[startLine]\n const startMax = state.eMarks[startLine]\n const lineText = state.src.slice(startPos, startMax)\n\n if (!QUIZ_RE.test(lineText)) return false\n if (silent) return true\n\n let nextLine = startLine + 1\n let found = false\n while (nextLine < endLine) {\n const pos = state.bMarks[nextLine] + state.tShift[nextLine]\n const max = state.eMarks[nextLine]\n const line = state.src.slice(pos, max)\n if (CLOSE_RE.test(line)) {\n found = true\n break\n }\n nextLine++\n }\n if (!found) return false\n\n const innerLines: string[] = []\n for (let i = startLine + 1; i < nextLine; i++) {\n const pos = state.bMarks[i] + state.tShift[i]\n const max = state.eMarks[i]\n innerLines.push(state.src.slice(pos, max))\n }\n\n const data = parseQuizBlock(innerLines)\n if (!data) return false\n\n const token = state.push(\"quiz\", \"\", 0)\n token.content = renderQuizComponent(data, escapeHtml)\n token.map = [startLine, nextLine + 1]\n token.block = true\n\n state.line = nextLine + 1\n return true\n}\n\n/* ── parser ──────────────────────────────────────────────────────────── */\n\nexport function parseQuizBlock(lines: string[]): QuizData | null {\n let question = \"\"\n const answers: QuizAnswer[] = []\n let explanation = \"\"\n const expected: string[] = []\n let shuffle = false\n\n for (const raw of lines) {\n const line = raw.trim()\n if (!line) continue\n\n if (line.startsWith(\"question:\")) {\n question = line.slice(\"question:\".length).trim()\n } else if (line.startsWith(\"answer-correct:\")) {\n answers.push({ text: line.slice(\"answer-correct:\".length).trim(), correct: true })\n } else if (line.startsWith(\"answer-input:\")) {\n expected.push(line.slice(\"answer-input:\".length).trim())\n } else if (line.startsWith(\"answer:\")) {\n answers.push({ text: line.slice(\"answer:\".length).trim(), correct: false })\n } else if (line.startsWith(\"explanation:\")) {\n explanation = line.slice(\"explanation:\".length).trim()\n } else if (line.startsWith(\"explication:\")) {\n // legacy French alias\n explanation = line.slice(\"explication:\".length).trim()\n } else if (line.startsWith(\"shuffle:\")) {\n shuffle = line.slice(\"shuffle:\".length).trim().toLowerCase() === \"true\"\n }\n }\n\n if (!question) return null\n\n if (expected.length > 0) {\n return { question, type: \"input\", answers: [], expected, explanation, shuffle: false }\n }\n\n if (answers.length === 0) return null\n return { question, type: \"choice\", answers, expected: [], explanation, shuffle }\n}\n\n/* ── renderer ────────────────────────────────────────────────────────── */\n\nfunction renderQuizComponent(data: QuizData, escapeHtml: (s: string) => string): string {\n const json = JSON.stringify(data)\n const escaped = escapeHtml(json)\n return `<QuizQuestion data-quiz=\"${escaped}\" />\\n`\n}\n","import type { QuizLocale } from \"./types/quiz\"\n\nexport const locales: Record<string, QuizLocale> = {\n en: {\n answered: \"answered\",\n validate: \"Validate\",\n reset: \"Restart\",\n correctAnswers: (n) => `correct answer${n !== 1 ? \"s\" : \"\"}`,\n multipleHint: \"Multiple answers possible\",\n explanation: \"Explanation: \",\n inputHint: \"Type your answer\",\n inputPlaceholder: \"Your answer…\",\n expectedAnswer: \"Expected answer:\",\n },\n fr: {\n answered: \"répondue(s)\",\n validate: \"Valider\",\n reset: \"Recommencer\",\n correctAnswers: (n) => `réponse${n > 1 ? \"s\" : \"\"} correcte${n > 1 ? \"s\" : \"\"}`,\n multipleHint: \"Plusieurs réponses possibles\",\n explanation: \"Explication : \",\n inputHint: \"Saisissez votre réponse\",\n inputPlaceholder: \"Votre réponse…\",\n expectedAnswer: \"Réponse attendue :\",\n },\n de: {\n answered: \"beantwortet\",\n validate: \"Überprüfen\",\n reset: \"Neu starten\",\n correctAnswers: (n) => `richtige Antwort${n !== 1 ? \"en\" : \"\"}`,\n multipleHint: \"Mehrere Antworten möglich\",\n explanation: \"Erklärung:\",\n inputHint: \"Geben Sie Ihre Antwort ein\",\n inputPlaceholder: \"Ihre Antwort…\",\n expectedAnswer: \"Erwartete Antwort:\",\n },\n it: {\n answered: \"risposta/e\",\n validate: \"Verifica\",\n reset: \"Ricominciare\",\n correctAnswers: (n) => `rispost${n !== 1 ? \"e corrette\" : \"a corretta\"}`,\n multipleHint: \"Più risposte possibili\",\n explanation: \"Spiegazione: \",\n inputHint: \"Digita la tua risposta\",\n inputPlaceholder: \"La tua risposta…\",\n expectedAnswer: \"Risposta attesa:\",\n },\n es: {\n answered: \"respondida(s)\",\n validate: \"Validar\",\n reset: \"Reiniciar\",\n correctAnswers: (n) => `respuesta${n !== 1 ? \"s correctas\" : \" correcta\"}`,\n multipleHint: \"Varias respuestas posibles\",\n explanation: \"Explicación: \",\n inputHint: \"Escribe tu respuesta\",\n inputPlaceholder: \"Tu respuesta…\",\n expectedAnswer: \"Respuesta esperada:\",\n },\n}\n\n/**\n * Get locale strings for a given language code.\n * Falls back to English if the language is not found.\n */\nexport function getLocale(lang = \"en\"): QuizLocale {\n return locales[lang] ?? locales.en\n}\n","/**\n * Inline markdown part — result of {@link parseRichText}.\n */\nexport type RichPart = { type: \"text\" | \"bold\" | \"italic\" | \"code\"; value: string }\n\n/**\n * Parse inline markdown subsets: **bold**, *italic*, `code` → typed parts array.\n * Used for question titles, answer text, and explanations.\n */\nexport function parseRichText(text: string): RichPart[] {\n const parts: RichPart[] = []\n const re = /(\\*\\*(.+?)\\*\\*)|(\\*(.+?)\\*)|(`([^`]+)`)/g\n let last = 0\n let m\n while ((m = re.exec(text)) !== null) {\n if (m.index > last) parts.push({ type: \"text\", value: text.slice(last, m.index) })\n if (m[2]) parts.push({ type: \"bold\", value: m[2] })\n else if (m[4]) parts.push({ type: \"italic\", value: m[4] })\n else if (m[6]) parts.push({ type: \"code\", value: m[6] })\n last = re.lastIndex\n }\n if (last < text.length) parts.push({ type: \"text\", value: text.slice(last) })\n return parts\n}\n","<script setup lang=\"ts\">\nimport { ref, computed, inject, watch, onMounted } from \"vue\"\nimport type { QuizData, QuizAnswer, QuizLocale, SavedAnswer } from \"./types/quiz\"\n\nconst props = defineProps({\n dataQuiz: { type: String, required: true },\n})\n\nconst rawQuiz = computed<QuizData | null>(() => {\n try {\n return JSON.parse(props.dataQuiz) as QuizData\n } catch {\n return null\n }\n})\n\n// Shuffle helper (Fisher-Yates)\nfunction shuffleArray<T>(arr: T[]): T[] {\n const a = [...arr]\n for (let i = a.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1))\n ;[a[i], a[j]] = [a[j], a[i]]\n }\n return a\n}\n\n// Shuffled answers — computed once at mount, re-shuffled on reset\nconst shuffledAnswers = ref<(QuizAnswer & { originalIndex: number })[]>([])\nfunction initAnswers() {\n if (!rawQuiz.value || rawQuiz.value.type === \"input\") {\n shuffledAnswers.value = []\n return\n }\n const indexed = rawQuiz.value.answers.map((a, i) => ({ ...a, originalIndex: i }))\n shuffledAnswers.value = rawQuiz.value.shuffle ? shuffleArray(indexed) : indexed\n}\n\n// Quiz data with shuffled answers\nconst quiz = computed(() => {\n if (!rawQuiz.value) return null\n return {\n ...rawQuiz.value,\n answers: shuffledAnswers.value,\n }\n})\n\nconst isInputMode = computed(() => rawQuiz.value?.type === 'input')\n\nconst correctCount = computed(() =>\n quiz.value && !isInputMode.value\n ? quiz.value.answers.filter((a) => a.correct).length\n : 0\n)\nconst isMultiple = computed(() => correctCount.value > 1)\n\n// Selected answer indices (for choice mode)\nconst selected = ref(new Set<number>())\n// Text input value (for fill-in-the-blank mode)\nconst inputValue = ref(\"\")\n\n// Registration with parent QuizPage\nconst register = inject<((q: { answered: typeof answered; isCorrect: typeof isCorrect }) => void) | null>(\"quiz-register\", null)\nconst validated = inject<ReturnType<typeof ref<boolean>>>(\"quiz-validated\", ref(false))\nconst resetCounter = inject<ReturnType<typeof ref<number>>>(\"quiz-reset\", ref(0))\nconst t = inject<QuizLocale>(\"quiz-locale\")!\n\n// Per-question persistence\nconst getQuestionId = inject<(() => number) | null>(\"quiz-question-id\", null)\nconst saveAnswer = inject<((id: number, data: SavedAnswer) => void) | null>(\"quiz-save-answer\", null)\nconst getAnswer = inject<((id: number) => SavedAnswer | null) | null>(\"quiz-get-answer\", null)\nconst myId: number | null = getQuestionId ? getQuestionId() : null\n\nconst answered = computed(() => {\n if (isInputMode.value) return inputValue.value.trim().length > 0\n return selected.value.size > 0\n})\n\nconst isCorrect = computed(() => {\n if (!quiz.value || !answered.value) return false\n\n if (isInputMode.value) {\n // Case-insensitive comparison against any accepted variant\n const input = inputValue.value.trim().toLowerCase()\n return rawQuiz.value!.expected.some((e) => input === e.trim().toLowerCase())\n }\n\n const correctIndices = new Set(\n quiz.value.answers\n .map((a, i) => (a.correct ? i : -1))\n .filter((i) => i >= 0)\n )\n if (selected.value.size !== correctIndices.size) return false\n for (const idx of selected.value) {\n if (!correctIndices.has(idx)) return false\n }\n return true\n})\n\n// Register this question with the parent page\nif (register) {\n register({ answered, isCorrect })\n}\n\n// Watch for reset from parent\nwatch(resetCounter, () => {\n selected.value = new Set()\n inputValue.value = ''\n initAnswers()\n})\n\nonMounted(() => {\n initAnswers()\n // Restore saved answer state\n if (getAnswer && myId !== null) {\n const saved = getAnswer(myId)\n if (saved) {\n if (saved.type === \"input\") {\n inputValue.value = saved.input\n } else if (saved.type === \"choice\") {\n selected.value = new Set(saved.selected)\n }\n }\n }\n})\n\nfunction toggle(idx: number) {\n if (validated.value) return\n const next = new Set(selected.value)\n if (isMultiple.value) {\n if (next.has(idx)) next.delete(idx)\n else next.add(idx)\n } else {\n next.clear()\n next.add(idx)\n }\n selected.value = next\n persistState()\n}\n\n// Save input value on change\nwatch(inputValue, () => {\n if (!validated.value) persistState()\n})\n\nfunction persistState() {\n if (!saveAnswer || myId === null) return\n if (isInputMode.value) {\n saveAnswer(myId, { type: \"input\", input: inputValue.value })\n } else {\n saveAnswer(myId, { type: \"choice\", selected: [...selected.value] })\n }\n}\n\nfunction answerClass(idx: number): string {\n if (!validated.value) {\n return selected.value.has(idx) ? \"quiz-answer selected\" : \"quiz-answer\"\n }\n const answer = quiz.value!.answers[idx]\n const wasPicked = selected.value.has(idx)\n if (answer.correct && wasPicked) return \"quiz-answer correct\"\n if (answer.correct && !wasPicked) return \"quiz-answer missed\"\n if (!answer.correct && wasPicked) return \"quiz-answer wrong\"\n return \"quiz-answer\"\n}\n\nconst inputClass = computed(() => {\n if (!validated.value) return \"quiz-input\"\n return isCorrect.value ? \"quiz-input correct\" : \"quiz-input wrong\"\n})\n\nimport { parseRichText, type RichPart } from './utils'\n</script>\n\n<template>\n <fieldset v-if=\"quiz\" class=\"quiz-question\" :class=\"{ validated: validated }\" :aria-label=\"quiz.question\">\n <legend class=\"quiz-question-title\">\n <template v-for=\"(part, pi) in parseRichText(quiz.question)\" :key=\"pi\">\n <strong v-if=\"part.type === 'bold'\">{{ part.value }}</strong>\n <em v-else-if=\"part.type === 'italic'\">{{ part.value }}</em>\n <code v-else-if=\"part.type === 'code'\">{{ part.value }}</code>\n <template v-else>{{ part.value }}</template>\n </template>\n </legend>\n\n <!-- Choice mode -->\n <template v-if=\"!isInputMode\">\n <p v-if=\"isMultiple\" class=\"quiz-hint\">{{ t.multipleHint }}</p>\n <ul class=\"quiz-answers\" role=\"listbox\" :aria-multiselectable=\"isMultiple\">\n <li\n v-for=\"(answer, idx) in quiz.answers\"\n :key=\"answer.originalIndex\"\n :class=\"answerClass(idx)\"\n @click=\"toggle(idx)\"\n role=\"option\"\n :aria-selected=\"selected.has(idx)\"\n tabindex=\"0\"\n @keydown.enter=\"toggle(idx)\"\n @keydown.space.prevent=\"toggle(idx)\"\n >\n <span class=\"quiz-indicator\" aria-hidden=\"true\">\n <template v-if=\"isMultiple\">\n <span v-if=\"selected.has(idx)\" class=\"quiz-check\">✓</span>\n <span v-else class=\"quiz-empty\">☐</span>\n </template>\n <template v-else>\n <span v-if=\"selected.has(idx)\" class=\"quiz-check\">●</span>\n <span v-else class=\"quiz-empty\">○</span>\n </template>\n </span>\n <span class=\"quiz-answer-text\">\n <template v-for=\"(part, pi) in parseRichText(answer.text)\" :key=\"pi\">\n <strong v-if=\"part.type === 'bold'\">{{ part.value }}</strong>\n <em v-else-if=\"part.type === 'italic'\">{{ part.value }}</em>\n <code v-else-if=\"part.type === 'code'\">{{ part.value }}</code>\n <template v-else>{{ part.value }}</template>\n </template>\n </span>\n </li>\n </ul>\n </template>\n\n <!-- Fill-in-the-blank mode -->\n <template v-if=\"isInputMode\">\n <p class=\"quiz-hint\">{{ t.inputHint }}</p>\n <div class=\"quiz-input-wrapper\">\n <input\n v-model=\"inputValue\"\n :class=\"inputClass\"\n type=\"text\"\n :disabled=\"validated\"\n :placeholder=\"t.inputPlaceholder\"\n :aria-label=\"quiz.question\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n @keydown.enter.prevent\n />\n <p v-if=\"validated && !isCorrect\" class=\"quiz-expected\">\n {{ t.expectedAnswer }} <code>{{ rawQuiz?.expected[0] }}</code>\n </p>\n </div>\n </template>\n\n <!-- Explanation (rich text: supports **bold** and `code`) -->\n <div v-if=\"validated && quiz.explanation\" class=\"quiz-explanation\" role=\"note\">\n <strong>{{ t.explanation }}</strong>\n <template v-for=\"(part, pi) in parseRichText(quiz.explanation)\" :key=\"pi\">\n <strong v-if=\"part.type === 'bold'\">{{ part.value }}</strong>\n <em v-else-if=\"part.type === 'italic'\">{{ part.value }}</em>\n <code v-else-if=\"part.type === 'code'\">{{ part.value }}</code>\n <template v-else>{{ part.value }}</template>\n </template>\n </div>\n </fieldset>\n</template>\n","<script setup lang=\"ts\">\nimport { ref, computed, provide, inject } from \"vue\"\nimport type { QuizLocale, QuizState, SavedAnswer } from \"./types/quiz\"\n\nconst t = inject<QuizLocale>(\"quiz-locale\")!\nconst questions = ref<QuizState[]>([])\nconst validated = ref(false)\n\n// Generate a storage key from the page path — set eagerly so children can read on mount\n// (Vue mounts children before parent, so onMounted would be too late)\nconst storageKey = typeof window !== 'undefined'\n ? 'quiz-state:' + window.location.pathname\n : ''\n\n// Restore quiz-level state immediately so validated is set before children mount\nrestoreState()\n\n// Question index counter for stable per-question storage keys\nlet questionIdx = 0\n\nprovide(\"quiz-validated\", validated)\nprovide(\"quiz-register\", (q: QuizState) => {\n questions.value.push(q)\n})\n\n// Per-question persistence: each question gets a unique sub-key\nprovide(\"quiz-question-id\", () => questionIdx++)\nprovide(\"quiz-save-answer\", (qId: number, data: SavedAnswer) => {\n if (!storageKey) return\n try {\n sessionStorage.setItem(storageKey + \":q\" + qId, JSON.stringify(data))\n } catch { /* ignore */ }\n})\nprovide(\"quiz-get-answer\", (qId: number): SavedAnswer | null => {\n if (!storageKey) return null\n try {\n const raw = sessionStorage.getItem(storageKey + \":q\" + qId)\n return raw ? JSON.parse(raw) : null\n } catch { return null }\n})\n\n// Provide a reset trigger for child components\nconst resetCounter = ref(0)\nprovide(\"quiz-reset\", resetCounter)\n\nconst totalQuestions = computed(() => questions.value.length)\nconst answeredCount = computed(() =>\n questions.value.filter((q) => q.answered).length\n)\nconst correctCount = computed(() =>\n questions.value.filter((q) => q.isCorrect).length\n)\nconst allAnswered = computed(() => answeredCount.value === totalQuestions.value)\nconst progressPct = computed(() =>\n totalQuestions.value ? Math.round((answeredCount.value / totalQuestions.value) * 100) : 0\n)\n\nfunction validate() {\n validated.value = true\n saveState()\n}\n\nfunction reset() {\n validated.value = false\n resetCounter.value++\n clearState()\n}\n\n/* ── sessionStorage persistence ───────────────────────────────────── */\nfunction saveState() {\n if (!storageKey) return\n try {\n const data = { validated: validated.value, ts: Date.now() }\n sessionStorage.setItem(storageKey, JSON.stringify(data))\n } catch { /* storage full or unavailable */ }\n}\n\nfunction restoreState() {\n if (!storageKey) return\n try {\n const raw = sessionStorage.getItem(storageKey)\n if (!raw) return\n const data = JSON.parse(raw)\n if (data && data.validated) {\n validated.value = true\n }\n } catch { /* corrupted – ignore */ }\n}\n\nfunction clearState() {\n if (!storageKey) return\n try {\n const keysToRemove: string[] = []\n for (let i = 0; i < sessionStorage.length; i++) {\n const key = sessionStorage.key(i)\n if (key && key.startsWith(storageKey)) {\n keysToRemove.push(key)\n }\n }\n keysToRemove.forEach((k) => sessionStorage.removeItem(k))\n } catch { /* ignore */ }\n}\n</script>\n\n<template>\n <div class=\"quiz-page\" role=\"region\" aria-label=\"Quiz\">\n <div class=\"quiz-progress-bar\" role=\"progressbar\"\n :aria-valuenow=\"answeredCount\"\n :aria-valuemin=\"0\"\n :aria-valuemax=\"totalQuestions\"\n :aria-label=\"answeredCount + ' / ' + totalQuestions + ' ' + t.answered\"\n >\n <div class=\"quiz-progress-track\">\n <div\n class=\"quiz-progress-fill\"\n :style=\"{ width: progressPct + '%' }\"\n :class=\"{ complete: progressPct === 100 }\"\n ></div>\n </div>\n <span class=\"quiz-progress-label\" aria-live=\"polite\">\n {{ answeredCount }} / {{ totalQuestions }} {{ t.answered }}\n </span>\n </div>\n\n <slot />\n\n <div class=\"quiz-actions\">\n <button\n v-if=\"!validated\"\n class=\"quiz-btn quiz-btn-validate\"\n :disabled=\"!allAnswered\"\n @click=\"validate\"\n >\n {{ t.validate }}\n </button>\n\n <template v-if=\"validated\">\n <div class=\"quiz-score\" role=\"status\" aria-live=\"polite\"\n :aria-label=\"correctCount + ' / ' + totalQuestions + ' ' + t.correctAnswers(correctCount)\"\n >\n <span class=\"quiz-score-value\">{{ correctCount }} / {{ totalQuestions }}</span>\n <span class=\"quiz-score-label\">\n {{ t.correctAnswers(correctCount) }}\n ({{ totalQuestions ? Math.round((correctCount / totalQuestions) * 100) : 0 }}%)\n </span>\n </div>\n <button class=\"quiz-btn quiz-btn-reset\" @click=\"reset\">\n {{ t.reset }}\n </button>\n </template>\n </div>\n </div>\n</template>\n","import type { App } from \"vue\"\nimport { ensureStylesInjected } from \"./styleManager\"\n\nexport { quizMarkdownPlugin } from \"./md-plugin\"\nexport { getLocale, locales } from \"./locales\"\nexport type { QuizData, QuizAnswer, QuizLocale, QuizState, SavedAnswer } from \"./types/quiz\"\n\nimport QuizQuestion from \"./QuizQuestion.vue\"\nimport QuizPage from \"./QuizPage.vue\"\nimport { getLocale as _getLocale } from \"./locales\"\n\nexport { QuizQuestion, QuizPage }\n\n/**\n * Register quiz components and locale in a VitePress `enhanceApp` hook.\n *\n * @example\n * // .vitepress/theme/index.ts\n * import { enhanceAppWithQuiz } from 'vitepress-plugin-quiz'\n * export default {\n * enhanceApp({ app }) {\n * enhanceAppWithQuiz(app) // English (default)\n * enhanceAppWithQuiz(app, 'fr') // French\n * }\n * }\n */\nexport function enhanceAppWithQuiz(app: App, lang = \"en\"): void {\n ensureStylesInjected()\n app.provide(\"quiz-locale\", _getLocale(lang))\n app.component(\"QuizQuestion\", QuizQuestion)\n app.component(\"QuizPage\", QuizPage)\n}\n"],"names":["stylesInjected","ensureStylesInjected","styleId","style","quizCssInline","QUIZ_RE","CLOSE_RE","quizMarkdownPlugin","md","escapeHtml","state","startLine","endLine","silent","quizBlockRule","tokens","idx","t","open","close","startPos","startMax","lineText","nextLine","found","pos","max","line","innerLines","i","data","parseQuizBlock","token","renderQuizComponent","lines","question","answers","explanation","expected","shuffle","raw","json","locales","n","getLocale","lang","parseRichText","text","parts","re","last","m","props","__props","rawQuiz","computed","shuffleArray","arr","a","j","shuffledAnswers","ref","initAnswers","indexed","quiz","isInputMode","correctCount","isMultiple","selected","inputValue","register","inject","validated","resetCounter","getQuestionId","saveAnswer","getAnswer","myId","answered","isCorrect","input","e","correctIndices","watch","onMounted","saved","toggle","next","persistState","answerClass","answer","wasPicked","inputClass","_createElementBlock","_normalizeClass","_unref","_createElementVNode","_hoisted_2","_Fragment","_renderList","part","pi","_hoisted_3","_toDisplayString","_hoisted_4","_hoisted_5","_createTextVNode","_openBlock","_hoisted_6","$event","_withKeys","_withModifiers","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","_hoisted_14","_hoisted_15","_hoisted_16","_hoisted_17","_hoisted_18","_hoisted_19","_hoisted_21","_hoisted_22","_hoisted_23","_hoisted_24","_hoisted_25","questions","storageKey","restoreState","questionIdx","provide","q","qId","totalQuestions","answeredCount","allAnswered","progressPct","validate","saveState","reset","clearState","keysToRemove","key","k","_hoisted_1","_renderSlot","_ctx","_hoisted_8","enhanceAppWithQuiz","app","_getLocale","QuizQuestion","QuizPage"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,96 @@
1
+ {
2
+ "name": "@matinfo/vitepress-plugin-quiz",
3
+ "version": "0.9.9",
4
+ "description": "A VitePress plugin to add interactive quizzes using :::quiz fenced blocks in Markdown",
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "type": "module",
9
+ "main": "./dist/vitepress-plugin-quiz.umd.cjs",
10
+ "module": "./dist/vitepress-plugin-quiz.js",
11
+ "types": "./dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/vitepress-plugin-quiz.js",
16
+ "require": "./dist/vitepress-plugin-quiz.umd.cjs",
17
+ "default": "./dist/vitepress-plugin-quiz.js"
18
+ },
19
+ "./package.json": "./package.json"
20
+ },
21
+ "files": [
22
+ "dist"
23
+ ],
24
+ "readme": "README.md",
25
+ "scripts": {
26
+ "build": "vite build",
27
+ "typecheck": "vue-tsc",
28
+ "pack": "bun pm pack",
29
+ "test:install": "bun run build && bun run pack && bun install --cwd test-project",
30
+ "test:dev": "bun run test:install && bun --cwd test-project run docs:dev",
31
+ "test:dev:only": "bun --cwd test-project run docs:dev",
32
+ "test:build": "bun run test:install && bun --cwd test-project run docs:build",
33
+ "test": "vitest run",
34
+ "test:watch": "vitest",
35
+ "lint": "eslint .",
36
+ "lint:fix": "eslint . --fix",
37
+ "format": "prettier --write .",
38
+ "audit": "bun audit --ignore GHSA-r5fr-rjxr-66jc --ignore GHSA-f23m-r3pf-42rh"
39
+ },
40
+ "keywords": [
41
+ "vitepress",
42
+ "vitepress-plugin",
43
+ "quiz",
44
+ "interactive",
45
+ "markdown",
46
+ "education",
47
+ "multiple-choice",
48
+ "fill-in-the-blank",
49
+ "i18n",
50
+ "vue"
51
+ ],
52
+ "license": "GPL-3.0-only",
53
+ "peerDependencies": {
54
+ "vue": "^3.0.0",
55
+ "vitepress": "^1.0.0"
56
+ },
57
+ "devDependencies": {
58
+ "@types/markdown-it": "^14.1.2",
59
+ "markdown-it": "^14.1.1",
60
+ "vitest": "^3.2.4",
61
+ "vue-tsc": "^2.2.12",
62
+ "@types/node": "^22.19.17",
63
+ "@typescript-eslint/eslint-plugin": "^8.58.0",
64
+ "@typescript-eslint/parser": "^8.58.0",
65
+ "@vitejs/plugin-vue": "^5.2.4",
66
+ "eslint": "^9.39.4",
67
+ "eslint-config-prettier": "^10.1.8",
68
+ "eslint-plugin-vue": "^9.33.0",
69
+ "globals": "^15.15.0",
70
+ "prettier": "3.4.2",
71
+ "typescript": "^5.9.3",
72
+ "typescript-eslint": "^8.58.0",
73
+ "vite": "^6.4.1",
74
+ "vite-plugin-dts": "^4.5.4",
75
+ "vitepress": "^1.6.4",
76
+ "vue": "^3.5.32",
77
+ "vue-eslint-parser": "^9.4.3"
78
+ },
79
+ "repository": {
80
+ "type": "git",
81
+ "url": "https://github.com/matinfo/vitepress-plugin-quiz.git"
82
+ },
83
+ "bugs": {
84
+ "url": "https://github.com/matinfo/vitepress-plugin-quiz/issues"
85
+ },
86
+ "homepage": "https://matinfo.github.io/vitepress-plugin-quiz/",
87
+ "engines": {
88
+ "node": ">=18.0.0"
89
+ },
90
+ "packageManager": "bun@1.2.0",
91
+ "overrides": {
92
+ "brace-expansion": "^1.1.13",
93
+ "esbuild": "^0.28.0",
94
+ "picomatch": "^4.0.4"
95
+ }
96
+ }