@octolearn/training-ui 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +397 -3
  3. package/THIRD-PARTY-NOTICES.md +211 -0
  4. package/dist/chunks/core-DR1lxtEg.js +562 -0
  5. package/dist/chunks/define-elements-BKBBQkbv.js +5515 -0
  6. package/dist/chunks/font-data-DlFp9eSH.js +8 -0
  7. package/dist/core.js +11 -0
  8. package/dist/define.js +49 -0
  9. package/dist/index.js +47 -0
  10. package/dist/octolearn-training-ui.bundle.js +5893 -0
  11. package/dist/types/base-element.d.ts +28 -0
  12. package/dist/types/content.d.ts +51 -0
  13. package/dist/types/core.d.ts +13 -0
  14. package/dist/types/d-icons.d.ts +10 -0
  15. package/dist/types/define-elements.d.ts +18 -0
  16. package/dist/types/define.d.ts +1 -0
  17. package/dist/types/diff.d.ts +34 -0
  18. package/dist/types/elements/arithmetic-question.d.ts +31 -0
  19. package/dist/types/elements/card.d.ts +42 -0
  20. package/dist/types/elements/choice-pair.d.ts +21 -0
  21. package/dist/types/elements/dictation-question.d.ts +42 -0
  22. package/dist/types/elements/feedback-toast.d.ts +29 -0
  23. package/dist/types/elements/feedback.d.ts +87 -0
  24. package/dist/types/elements/flashcard.d.ts +46 -0
  25. package/dist/types/elements/matching-round.d.ts +61 -0
  26. package/dist/types/elements/multiple-choice.d.ts +33 -0
  27. package/dist/types/elements/picture-question.d.ts +18 -0
  28. package/dist/types/elements/progress.d.ts +24 -0
  29. package/dist/types/elements/question-answer.d.ts +22 -0
  30. package/dist/types/elements/question-parts.d.ts +80 -0
  31. package/dist/types/elements/question.d.ts +37 -0
  32. package/dist/types/elements/text-answer.d.ts +50 -0
  33. package/dist/types/elements/tile-answer.d.ts +43 -0
  34. package/dist/types/elements/today-stats.d.ts +17 -0
  35. package/dist/types/elements/trainer-overlay.d.ts +45 -0
  36. package/dist/types/elements/trainer-panel.d.ts +46 -0
  37. package/dist/types/elements/trainer.d.ts +57 -0
  38. package/dist/types/elements/true-false.d.ts +37 -0
  39. package/dist/types/events.d.ts +53 -0
  40. package/dist/types/feedback-message.d.ts +34 -0
  41. package/dist/types/font-data.d.ts +2 -0
  42. package/dist/types/fonts.d.ts +9 -0
  43. package/dist/types/i18n/strings.d.ts +228 -0
  44. package/dist/types/icons.d.ts +21 -0
  45. package/dist/types/images.d.ts +2 -0
  46. package/dist/types/index.d.ts +31 -0
  47. package/dist/types/keys.d.ts +6 -0
  48. package/dist/types/session/third-party-transport.d.ts +22 -0
  49. package/dist/types/session/training-session.d.ts +167 -0
  50. package/dist/types/session/transport.d.ts +44 -0
  51. package/dist/types/speech.d.ts +54 -0
  52. package/dist/types/styles/base.d.ts +9 -0
  53. package/dist/types/styles/d-parts.d.ts +12 -0
  54. package/dist/types/styles/tokens.d.ts +95 -0
  55. package/package.json +67 -6
@@ -0,0 +1,80 @@
1
+ import { nothing, type PropertyValues, type TemplateResult } from 'lit';
2
+ import { OctolearnElement } from '../base-element';
3
+ import type { FrontendContent, MatchingRound } from '../content';
4
+ import type { SpeakEventDetail } from '../events';
5
+ import { type TrainingLanguage, type TrainingStrings } from '../i18n/strings';
6
+ import { type SpeakOptions } from '../speech';
7
+ import type { FlashcardRevealer } from './flashcard';
8
+ /** The look shared by the question elements in design D. */
9
+ export declare const questionStyles: import("lit").CSSResult;
10
+ /**
11
+ * Base of the question elements. A new `content` is a new question: the answer field is emptied, and with
12
+ * `autofocusAnswer` the cursor goes into it. `speak()` reads text aloud through a cancelable `octolearn-speak` event, so a
13
+ * page with its own voice output can take over; otherwise the built-in SpeechController speaks and, if the browser
14
+ * blocks speech until the first tap, a "Abspielen" hint appears.
15
+ */
16
+ export declare class QuestionElement extends OctolearnElement {
17
+ static styles: import("lit").CSSResultGroup[];
18
+ /** The question as octolearn's API sends it. */
19
+ content?: FrontendContent;
20
+ /** Passed to the answer tiles: don't take the number keys. */
21
+ noKeys: boolean;
22
+ /** Fetches the answer of a Karteikarte (octolearn's web app), e.g. `content => session.revealFlashcard(content)`. */
23
+ revealFlashcard?: FlashcardRevealer;
24
+ protected needsGesture: boolean;
25
+ protected autofocusAnswer: boolean;
26
+ protected readonly speech: import("..").SpeechController;
27
+ connectedCallback(): void;
28
+ disconnectedCallback(): void;
29
+ /** Reads text aloud, unless the page cancels the `octolearn-speak` event and speaks itself. */
30
+ protected speakText(text: string | null | undefined, reason: SpeakEventDetail['reason'], options?: SpeakOptions): void;
31
+ protected playPending(): void;
32
+ protected playHint(t: TrainingStrings): TemplateResult | typeof nothing;
33
+ protected updated(changed: PropertyValues<this>): void;
34
+ /** Puts the focus on the answer: the field, the first tile or the first button (e.g. when an overlay opens). */
35
+ focusAnswer(): void;
36
+ }
37
+ export interface AnswerSectionOptions {
38
+ content: FrontendContent;
39
+ lang: TrainingLanguage;
40
+ strings?: Partial<TrainingStrings>;
41
+ t: TrainingStrings;
42
+ /** Accessible name of the text field. */
43
+ inputLabel: string;
44
+ /** Show the field's name above it (D: "Auf Englisch", "Schreib das Wort"). */
45
+ visibleLabel?: boolean;
46
+ /** Accessible name of the answer tiles. */
47
+ choiceLabel: string;
48
+ inputType?: 'text' | 'number';
49
+ /** Language of the typed answer. */
50
+ inputLang?: string;
51
+ noKeys?: boolean;
52
+ /** Arithmetic: the task left of a number box. */
53
+ before?: TemplateResult;
54
+ /** A picture left of the field. */
55
+ media?: TemplateResult;
56
+ /** Karteikarte: fetches the answer. */
57
+ reveal?: FlashcardRevealer;
58
+ }
59
+ /**
60
+ * The answer part every question shares: the tiles for a multiple-choice question, the field otherwise. An unknown format
61
+ * shows nothing, like octolearn.
62
+ */
63
+ export declare function answerSection(options: AnswerSectionOptions): TemplateResult | typeof nothing;
64
+ /** "en" → "Englisch" (in German texts), via the browser's language names; unknown codes stay as they are. */
65
+ export declare function languageName(code: string | null | undefined, lang: TrainingLanguage): string | undefined;
66
+ /**
67
+ * What the card around a question shows: the format label ("Diktat", "Wähle die richtige Antwort") and, for vocabulary,
68
+ * the direction as chip ("Deutsch → Englisch").
69
+ */
70
+ export declare function describeQuestion(content: FrontendContent, language?: string, overrides?: Partial<TrainingStrings>): {
71
+ label: string;
72
+ chip?: string;
73
+ };
74
+ /** What the card around a round of "Paare finden" shows: the label and the folder as chip. */
75
+ export declare function describeMatchingRound(round: MatchingRound, language?: string, overrides?: Partial<TrainingStrings>): {
76
+ label: string;
77
+ chip?: string;
78
+ };
79
+ /** "Wie heißt das auf Englisch?" when the target language is known, else octolearn's "Übersetze folgendes Wort:". */
80
+ export declare function vocabularyPrompt(content: FrontendContent, lang: TrainingLanguage, t: TrainingStrings): string;
@@ -0,0 +1,37 @@
1
+ import { type TemplateResult } from 'lit';
2
+ import { OctolearnElement } from '../base-element';
3
+ import type { FrontendContent } from '../content';
4
+ import type { FlashcardRevealer } from './flashcard';
5
+ /**
6
+ * `<octolearn-question>`: shows any question the API sends, picking the element by its answer format first, then by its
7
+ * learning mode, like octolearn's training page. The attributes of the specific elements (`settings`, `no-autospeak`,
8
+ * `no-autofocus`) are passed on.
9
+ *
10
+ * @fires octolearn-answer - `{ answer }`
11
+ * @fires octolearn-speak - see octolearn-dictation-question
12
+ * @fires octolearn-stop - see octolearn-dictation-question
13
+ * @fires octolearn-settings - see octolearn-dictation-question
14
+ */
15
+ export declare class OctolearnQuestion extends OctolearnElement {
16
+ content?: FrontendContent;
17
+ settings: boolean;
18
+ noAutospeak: boolean;
19
+ noAutofocus: boolean;
20
+ /** Don't let the answer tiles take the number keys 1–9 (for a game that uses them itself). */
21
+ noKeys: boolean;
22
+ /** Fetches the answer of a Karteikarte (octolearn's web app), e.g. `content => session.revealFlashcard(content)`. */
23
+ revealFlashcard?: FlashcardRevealer;
24
+ /** The element showing the current question, if any. */
25
+ get questionElement(): HTMLElement | null;
26
+ /** Puts the focus on the answer of the current question. */
27
+ focusAnswer(): void;
28
+ /** For a dictation: puts the focus back on "Einstellungen" (after the page's voice settings close). */
29
+ focusSettings(): void;
30
+ render(): TemplateResult;
31
+ private renderQuestion;
32
+ }
33
+ declare global {
34
+ interface HTMLElementTagNameMap {
35
+ 'octolearn-question': OctolearnQuestion;
36
+ }
37
+ }
@@ -0,0 +1,50 @@
1
+ import { type TemplateResult } from 'lit';
2
+ import { OctolearnElement } from '../base-element';
3
+ /**
4
+ * `<octolearn-text-answer>`: design D's typed answer. The big field, below it "Weiß ich nicht" and, on the right,
5
+ * "Enter drücken oder" + "Fertig". Enter (also a phone keyboard's Go key) sends; an empty answer is never sent and
6
+ * "Fertig" stays disabled until something is typed. "Weiß ich nicht" sends "?" with `dontKnow: true`, which the server
7
+ * grades wrong and answers with the solution. The field empties after sending.
8
+ *
9
+ * `variant="box"` is the arithmetic look: a square box for the number, with whatever is in the `before` slot (the task,
10
+ * "7 · 8 =") on its left.
11
+ *
12
+ * `variant="media"` puts whatever is in the `media` slot (a picture) left of the field, the buttons below both.
13
+ *
14
+ * With `hint` (a Wortfragment, OC-126: "S____e") the known letters stand big above the field, each missing one a dashed
15
+ * box (design D's Lückenwort look); screen readers hear "Hinweis: 6 Zeichen, beginnt mit „S“, endet mit „e“.".
16
+ *
17
+ * @slot before - only with variant="box": shown left of the box
18
+ * @slot media - only with variant="media": shown left of the field
19
+ * @fires octolearn-answer - `{ answer, dontKnow? }`
20
+ */
21
+ export declare class OctolearnTextAnswer extends OctolearnElement {
22
+ static styles: import("lit").CSSResultGroup[];
23
+ type: 'text' | 'number';
24
+ /** Accessible name of the field (visually hidden unless `visible-label`). */
25
+ label: string;
26
+ /** Show the label above the field (D: "Auf Englisch", "Schreib das Wort"). */
27
+ visibleLabel: boolean;
28
+ placeholder: string;
29
+ /** Language of what is typed, e.g. "en" for a vocabulary answer (spell checkers and screen readers use it). */
30
+ inputLang?: string;
31
+ variant: 'field' | 'box' | 'media';
32
+ /** Hide "Weiß ich nicht". */
33
+ noDontKnow: boolean;
34
+ value: string;
35
+ /** Wortfragment: first and last letter, "_" for each letter between. */
36
+ hint?: string | null;
37
+ private input?;
38
+ /** Puts the cursor into the field. */
39
+ focus(options?: FocusOptions): void;
40
+ render(): TemplateResult;
41
+ private renderHint;
42
+ private onInput;
43
+ private onSubmit;
44
+ private onDontKnow;
45
+ }
46
+ declare global {
47
+ interface HTMLElementTagNameMap {
48
+ 'octolearn-text-answer': OctolearnTextAnswer;
49
+ }
50
+ }
@@ -0,0 +1,43 @@
1
+ import { type PropertyValues, type TemplateResult } from 'lit';
2
+ import { OctolearnElement } from '../base-element';
3
+ /**
4
+ * `<octolearn-tile-answer>`: design D's "Buchstabensalat" (OC-121…124): the shuffled letters or words of the answer, tapped
5
+ * into the right order. Above, the answer slots (the next one highlighted, the free ones dashed); below a dashed line the
6
+ * tiles, each keeping its place when used. Tapping a placed tile takes it out again; "Nochmal von vorn" empties the slots;
7
+ * "Fertig" sends once every tile is placed. Every tile is a button (touch, mouse, keyboard, no dragging, WCAG 2.5.7);
8
+ * with the focus inside, typing a letter places the next fitting tile, Backspace takes the last one out, Enter sends.
9
+ *
10
+ * The answer is the tiles joined with `separator`: "" for letters, " " for words. The server checks it like a typed
11
+ * answer.
12
+ *
13
+ * @fires octolearn-answer - `{ answer }`
14
+ */
15
+ export declare class OctolearnTileAnswer extends OctolearnElement {
16
+ static styles: import("lit").CSSResultGroup[];
17
+ /** The shuffled tiles from the server (`content.tiles`). */
18
+ tiles: readonly string[] | null;
19
+ /** "" joins letters into a word, " " joins words into a sentence. */
20
+ separator: string;
21
+ private bank;
22
+ private placed;
23
+ private firstFreeTile?;
24
+ private get words();
25
+ get complete(): boolean;
26
+ /** The answer so far. */
27
+ get answer(): string;
28
+ /** Puts the focus on the first free tile, so typing works at once. */
29
+ focus(options?: FocusOptions): void;
30
+ protected willUpdate(changed: PropertyValues<this>): void;
31
+ render(): TemplateResult;
32
+ private place;
33
+ private takeOut;
34
+ private reset;
35
+ private submit;
36
+ /** A character places the first free tile that starts with it (the same case first), Backspace undoes, Enter sends. */
37
+ private onKeydown;
38
+ }
39
+ declare global {
40
+ interface HTMLElementTagNameMap {
41
+ 'octolearn-tile-answer': OctolearnTileAnswer;
42
+ }
43
+ }
@@ -0,0 +1,17 @@
1
+ import { type TemplateResult } from 'lit';
2
+ import { OctolearnElement } from '../base-element';
3
+ /**
4
+ * `<octolearn-today-stats>`: today's right and wrong answers in design D: a small paper panel with the uppercase label
5
+ * and two counters, green with a check and red with a cross. Side by side when there is room, else stacked.
6
+ */
7
+ export declare class OctolearnTodayStats extends OctolearnElement {
8
+ static styles: import("lit").CSSResultGroup[];
9
+ correct: number;
10
+ wrong: number;
11
+ render(): TemplateResult;
12
+ }
13
+ declare global {
14
+ interface HTMLElementTagNameMap {
15
+ 'octolearn-today-stats': OctolearnTodayStats;
16
+ }
17
+ }
@@ -0,0 +1,45 @@
1
+ import { type PropertyValues, type TemplateResult } from 'lit';
2
+ import { OctolearnElement } from '../base-element';
3
+ import type { TrainingSession } from '../session/training-session';
4
+ /**
5
+ * `<octolearn-trainer-overlay>`: design D's question over a paused game. While `open`, a modal dialog covers the page:
6
+ * the game stays visible behind a dark, blurred layer with the note "Spiel pausiert", the card sits in the middle. The
7
+ * page behind is inert, so the keyboard and screen readers stay in the dialog; when it closes, the focus goes back to
8
+ * where it was.
9
+ *
10
+ * With `.session` the overlay shows an `<octolearn-trainer>` driven by that session; without one, it shows its children
11
+ * (e.g. your own `<octolearn-card>`). Escape fires `octolearn-close` and leaves the overlay open: the game decides
12
+ * whether the learner may skip the question (set `open = false`).
13
+ *
14
+ * @slot - the content when no session is set
15
+ * @fires octolearn-close - the learner pressed Escape (or the system's back gesture)
16
+ * @cssprop --octolearn-overlay-width - width of the card (default 760px)
17
+ */
18
+ export declare class OctolearnTrainerOverlay extends OctolearnElement {
19
+ static styles: import("lit").CSSResultGroup[];
20
+ open: boolean;
21
+ /** The session that drives the trainer inside. */
22
+ session?: TrainingSession;
23
+ /** The note over the game (default "Spiel pausiert"); `status=""` hides it. */
24
+ status?: string;
25
+ /** Passed to the trainer: don't read a new dictation aloud by itself. */
26
+ noAutospeak: boolean;
27
+ /** Passed to the trainer: don't take the number and arrow keys. */
28
+ noKeys: boolean;
29
+ private dialog?;
30
+ /** Opens the overlay (same as `open = true`). */
31
+ show(): void;
32
+ /** Closes the overlay (same as `open = false`). */
33
+ close(): void;
34
+ protected updated(changed: PropertyValues<this>): void;
35
+ render(): TemplateResult;
36
+ private onKeydown;
37
+ private onCancel;
38
+ /** The browser closed the dialog anyway (it may, after repeated close requests): follow it. */
39
+ private onClose;
40
+ }
41
+ declare global {
42
+ interface HTMLElementTagNameMap {
43
+ 'octolearn-trainer-overlay': OctolearnTrainerOverlay;
44
+ }
45
+ }
@@ -0,0 +1,46 @@
1
+ import { type PropertyValues, type TemplateResult } from 'lit';
2
+ import { OctolearnElement } from '../base-element';
3
+ import type { TrainingSession } from '../session/training-session';
4
+ /**
5
+ * `<octolearn-trainer-panel>`: design D's side panel next to a game that keeps running. On top the octolearn logo, the
6
+ * label "Lernfrage" and a star counter; below the question card; then the game's reward (slot `reward`, e.g. "Richtig
7
+ * = 1 Extraleben"); at the bottom Inkie saying how many questions are left in the round.
8
+ *
9
+ * With `.session` everything follows that session (card, stars = today's right answers, questions left); without one
10
+ * the panel shows its children in place of the card, and `stars` / `message` say what to show. The panel is 400 px
11
+ * wide by default; size it like any block element.
12
+ *
13
+ * @slot - the card when no session is set
14
+ * @slot reward - what the game gives for a right answer
15
+ */
16
+ export declare class OctolearnTrainerPanel extends OctolearnElement {
17
+ static styles: import("lit").CSSResultGroup[];
18
+ /** The session that drives the panel. */
19
+ session?: TrainingSession;
20
+ /** The star counter; default: the session's right answers today. */
21
+ stars?: number;
22
+ /** Inkie's line; default: the questions left in the session's round ("Noch 2 Fragen in dieser Runde!"). */
23
+ message?: string;
24
+ /** Passed to the trainer: don't read a new dictation aloud by itself. */
25
+ noAutospeak: boolean;
26
+ /** Passed to the trainer: don't take the number and arrow keys (a running game usually needs them). */
27
+ noKeys: boolean;
28
+ /** Passed to the trainer: don't move the cursor into the answer field (the game keeps the keyboard). */
29
+ noAutofocus: boolean;
30
+ private hasReward;
31
+ private observed?;
32
+ private readonly onChange;
33
+ connectedCallback(): void;
34
+ disconnectedCallback(): void;
35
+ protected willUpdate(changed: PropertyValues<this>): void;
36
+ render(): TemplateResult;
37
+ /** "Noch 2 Fragen in dieser Runde!" from the session's stars; nothing while no question is asked. */
38
+ private roundMessage;
39
+ private onRewardChange;
40
+ private observe;
41
+ }
42
+ declare global {
43
+ interface HTMLElementTagNameMap {
44
+ 'octolearn-trainer-panel': OctolearnTrainerPanel;
45
+ }
46
+ }
@@ -0,0 +1,57 @@
1
+ import { nothing, type PropertyValues, type TemplateResult } from 'lit';
2
+ import { OctolearnElement } from '../base-element';
3
+ import type { TrainingSession } from '../session/training-session';
4
+ /**
5
+ * `<octolearn-trainer>`: a whole training in design D's card, driven by a TrainingSession. It shows what the session is
6
+ * at: the question (any format), the feedback after an answer with "Weiter", a round of "Paare finden", or a message
7
+ * while loading, after an error ("Erneut versuchen"), when everything due is done ("Freiwillig weiterüben") and when
8
+ * nothing is left. Answers, "Weiter" and the pairs go to the session; the stars follow its round.
9
+ *
10
+ * Create the session with `holdForFeedback: true` to see the feedback in the card. Don't call session.answer() yourself
11
+ * as well: the trainer does. The question's events (octolearn-answer, octolearn-speak, …) still bubble out.
12
+ *
13
+ * ```js
14
+ * const session = new TrainingSession(transport, { holdForFeedback: true });
15
+ * trainer.session = session;
16
+ * await session.start();
17
+ * ```
18
+ */
19
+ export declare class OctolearnTrainer extends OctolearnElement {
20
+ static styles: import("lit").CSSResultGroup[];
21
+ /** The session that drives the trainer. */
22
+ session?: TrainingSession;
23
+ /** Don't read a new dictation aloud by itself. */
24
+ noAutospeak: boolean;
25
+ /** Don't move the cursor into the answer field of a new question. */
26
+ noAutofocus: boolean;
27
+ /** Don't take the number and arrow keys (for a game that needs them itself). */
28
+ noKeys: boolean;
29
+ /** Show "Einstellungen" in a dictation (fires octolearn-settings). */
30
+ settings: boolean;
31
+ /** For the side panel: a card without header and Inkie, with a light shadow. */
32
+ compact: boolean;
33
+ /** A lighter shadow, for a trainer that sits on the page instead of over a game. */
34
+ flat: boolean;
35
+ private observed?;
36
+ private shownFeedback;
37
+ private readonly onChange;
38
+ private readonly reveal;
39
+ private readonly checkPair;
40
+ connectedCallback(): void;
41
+ disconnectedCallback(): void;
42
+ protected willUpdate(changed: PropertyValues<this>): void;
43
+ /** Puts the focus where the learner goes on: the answer, "Weiter" after an answer, or the first button. */
44
+ focusAnswer(): void;
45
+ /** For a dictation: puts the focus back on "Einstellungen" (after the page's voice settings close). */
46
+ focusSettings(): void;
47
+ protected updated(): void;
48
+ render(): TemplateResult | typeof nothing;
49
+ /** Loading, an error, everything due done, nothing left. */
50
+ private statusMessage;
51
+ private observe;
52
+ }
53
+ declare global {
54
+ interface HTMLElementTagNameMap {
55
+ 'octolearn-trainer': OctolearnTrainer;
56
+ }
57
+ }
@@ -0,0 +1,37 @@
1
+ import { nothing, type PropertyValues, type TemplateResult } from 'lit';
2
+ import { OctolearnElement } from '../base-element';
3
+ /** What the server takes as the answer to a Richtig/Falsch question (OC-127). */
4
+ export declare const TRUE_ANSWER = "true";
5
+ export declare const FALSE_ANSWER = "false";
6
+ /**
7
+ * `<octolearn-true-false>`: design D's "Stimmt das?" (OC-127). The server sends a statement, the question's answer or
8
+ * another answer of the folder; the learner says whether it fits. Which one it is, the client never knows. "Stimmt" sends
9
+ * "true", "Stimmt nicht" "false"; ← and → choose too (not while typing, not with `no-keys`). The buttons lock after the
10
+ * choice until a new statement arrives.
11
+ *
12
+ * @fires octolearn-answer - `{ answer: 'true' | 'false' }`
13
+ */
14
+ export declare class OctolearnTrueFalse extends OctolearnElement {
15
+ static styles: import("lit").CSSResultGroup[];
16
+ /** The answer to judge (`content.statement`); without one nothing is shown. */
17
+ statement?: string | null;
18
+ /** Language of the statement (the target language of a vocabulary). */
19
+ statementLang?: string;
20
+ /** Accessible name of the two buttons (default "Passt diese Antwort zur Frage?"). */
21
+ label?: string;
22
+ /** Don't react to ← and →. */
23
+ noKeys: boolean;
24
+ private chosen;
25
+ connectedCallback(): void;
26
+ disconnectedCallback(): void;
27
+ protected willUpdate(changed: PropertyValues<this>): void;
28
+ private get choices();
29
+ render(): TemplateResult | typeof nothing;
30
+ private choose;
31
+ private readonly onKeyDown;
32
+ }
33
+ declare global {
34
+ interface HTMLElementTagNameMap {
35
+ 'octolearn-true-false': OctolearnTrueFalse;
36
+ }
37
+ }
@@ -0,0 +1,53 @@
1
+ import type { MatchingRoundItem } from './content';
2
+ /** Fired by every element that takes an answer; bubbles out of shadow roots. */
3
+ export interface AnswerEventDetail {
4
+ /** What the learner typed (trimmed) or chose. Correctness is decided by the server, never here. */
5
+ answer: string;
6
+ /** "Weiß ich nicht": `answer` is then "?", which the server grades wrong and answers with the solution. */
7
+ dontKnow?: boolean;
8
+ }
9
+ export type AnswerEvent = CustomEvent<AnswerEventDetail>;
10
+ export declare const ANSWER_EVENT = "octolearn-answer";
11
+ /** What "Weiß ich nicht" sends: never a real answer, so the server grades it wrong and returns the solution. */
12
+ export declare const DONT_KNOW_ANSWER = "?";
13
+ /** Fired before anything is read aloud; cancel it to speak with your own voice output. */
14
+ export interface SpeakEventDetail {
15
+ /** The text to read aloud. */
16
+ text: string;
17
+ /**
18
+ * `auto`: a new dictation question arrived; `repeat`: the listen button; `slow`: "Langsam anhören"; `read`: the
19
+ * read-aloud button of a word, question or task.
20
+ */
21
+ reason: 'auto' | 'repeat' | 'slow' | 'read';
22
+ /** A speed for this request (0.7 for `slow`). */
23
+ rate?: number;
24
+ /** The language of the text, when it is not the page's (a vocabulary word). */
25
+ lang?: string;
26
+ }
27
+ export type SpeakEvent = CustomEvent<SpeakEventDetail>;
28
+ /** Fired by `<octolearn-matching-round>` after the server checked a pair. */
29
+ export interface PairCheckedDetail {
30
+ item: MatchingRoundItem;
31
+ /** The answer the learner paired the question with. */
32
+ answer: string;
33
+ correct: boolean;
34
+ /** After a wrong pair: the question's real answer. */
35
+ correctAnswer?: string | null;
36
+ }
37
+ interface OctolearnEventMap {
38
+ 'octolearn-answer': AnswerEvent;
39
+ 'octolearn-speak': SpeakEvent;
40
+ 'octolearn-stop': CustomEvent<Record<string, never>>;
41
+ 'octolearn-settings': CustomEvent<Record<string, never>>;
42
+ 'octolearn-continue': CustomEvent<Record<string, never>>;
43
+ 'octolearn-pair': CustomEvent<PairCheckedDetail>;
44
+ 'octolearn-round-done': CustomEvent<Record<string, never>>;
45
+ 'octolearn-close': CustomEvent<Record<string, never>>;
46
+ }
47
+ declare global {
48
+ interface HTMLElementEventMap extends OctolearnEventMap {
49
+ }
50
+ interface DocumentEventMap extends OctolearnEventMap {
51
+ }
52
+ }
53
+ export {};
@@ -0,0 +1,34 @@
1
+ import type { QueryFormat } from './content';
2
+ /** How a question of the round went (design D's stars). */
3
+ export type QuestionResult = 'right' | 'wrong';
4
+ export type FeedbackResult = 'correct' | 'wrong';
5
+ /** Everything the feedback shows about one evaluated answer; `TrainingSession` builds it (AnswerOutcome.feedback). */
6
+ export interface FeedbackMessage {
7
+ result: FeedbackResult;
8
+ /** What the learner answered. */
9
+ answer: string;
10
+ /** The solution, sent by the server after a wrong answer. */
11
+ correctAnswer?: string | null;
12
+ /** Accepted with a small typo. */
13
+ typo?: boolean;
14
+ /** Shown in brackets after "Richtig!" text instead of the typo note, e.g. the server's message. */
15
+ note?: string | null;
16
+ /** The learner pressed "Weiß ich nicht". */
17
+ dontKnow?: boolean;
18
+ /** The answer could not be sent or checked. */
19
+ unchecked?: boolean;
20
+ /** Learning points this answer earned (shown only after a right answer). */
21
+ points?: number;
22
+ /** Right answers in a row, this one included. */
23
+ streak?: number;
24
+ /** For a multiple-choice question: the options, shown again with the right one marked. */
25
+ options?: readonly string[] | null;
26
+ /** The question was a word (dictation, vocabulary): "das Wort kommt bald wieder", listen again. */
27
+ word?: boolean;
28
+ /** A dictation: the solution can be listened to again. */
29
+ listenable?: boolean;
30
+ /** How the question was answered; Richtig/Falsch and the Karteikarte show "Stimmt" / "Gewusst" instead of the token. */
31
+ queryFormat?: QueryFormat | null;
32
+ /** Toast only: how long the card stays, in ms. */
33
+ life?: number;
34
+ }
@@ -0,0 +1,2 @@
1
+ export declare const montserratLatinVariable: string;
2
+ export declare const nothingYouCouldDoLatin400: string;
@@ -0,0 +1,9 @@
1
+ /** Font family names of our own, so that a page's own "Montserrat" (other weights, other files) can't get mixed in. */
2
+ export declare const FONT_FAMILY_BODY = "Octolearn Montserrat";
3
+ export declare const FONT_FAMILY_HEADLINE = "Octolearn Headline";
4
+ /**
5
+ * Adds the fonts to the document. Font faces declared inside a shadow root are ignored by browsers, so they have to be
6
+ * added to the document; the FontFace API needs no <style> element (and so no 'unsafe-inline' in a page's CSP). A page
7
+ * whose CSP forbids data: fonts keeps the fallback fonts (Montserrat if the page has it, else sans-serif).
8
+ */
9
+ export declare function loadFonts(): Promise<void>;