@erudit-js/prose 4.0.1 → 4.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.
- package/dist/app/composables/context.d.ts +6 -1
- package/dist/app/language/element.d.ts +1 -1
- package/dist/elements/accent/Accent.vue +1 -0
- package/dist/elements/diagram/Diagram.vue +6 -10
- package/dist/elements/link/BlockLink.vue +117 -66
- package/dist/elements/link/Link.vue +38 -11
- package/dist/elements/link/core.js +1 -1
- package/dist/elements/link/dependency/app.d.ts +2 -2
- package/dist/elements/link/dependency/core.d.ts +12 -18
- package/dist/elements/link/dependency/core.js +1 -17
- package/dist/elements/link/reference/languages/en.d.ts +2 -3
- package/dist/elements/link/reference/languages/en.js +5 -1
- package/dist/elements/link/reference/languages/ru.d.ts +2 -3
- package/dist/elements/link/reference/languages/ru.js +5 -1
- package/dist/elements/link/reference/phrases.d.ts +5 -0
- package/dist/elements/link/reference/phrases.js +1 -0
- package/dist/elements/link/step.d.ts +16 -0
- package/dist/elements/link/step.js +36 -0
- package/dist/elements/link/storage.d.ts +9 -5
- package/dist/elements/link/storage.js +4 -4
- package/dist/elements/math/_global.d.ts +7 -0
- package/dist/elements/math/block.d.ts +2 -0
- package/dist/elements/math/block.js +42 -29
- package/dist/elements/math/components/MathGroup.vue +20 -3
- package/dist/elements/problem/_global.d.ts +174 -29
- package/dist/elements/problem/app.d.ts +7 -7
- package/dist/elements/problem/app.js +13 -12
- package/dist/elements/problem/components/ProblemButtonGenerate.vue +96 -0
- package/dist/elements/problem/components/ProblemContent.vue +14 -104
- package/dist/elements/problem/components/expanders/Check.vue +58 -11
- package/dist/elements/problem/components/expanders/Checks.vue +5 -5
- package/dist/elements/problem/components/expanders/DefaultPlusSections.vue +0 -2
- package/dist/elements/problem/core.d.ts +55 -28
- package/dist/elements/problem/core.js +2 -1
- package/dist/elements/problem/languages/{en.d.ts → problem/en.d.ts} +1 -1
- package/dist/elements/problem/languages/problem/en.js +6 -0
- package/dist/elements/problem/languages/{ru.d.ts → problem/ru.d.ts} +1 -1
- package/dist/elements/problem/languages/problem/ru.js +6 -0
- package/dist/elements/problem/languages/problems/en.d.ts +3 -0
- package/dist/elements/problem/languages/problems/en.js +6 -0
- package/dist/elements/problem/languages/problems/ru.d.ts +3 -0
- package/dist/elements/problem/languages/problems/ru.js +6 -0
- package/dist/elements/problem/languages/shared/en.d.ts +3 -0
- package/dist/elements/problem/languages/{en.js → shared/en.js} +12 -3
- package/dist/elements/problem/languages/shared/ru.d.ts +3 -0
- package/dist/elements/problem/languages/{ru.js → shared/ru.js} +12 -3
- package/dist/elements/problem/phrases.d.ts +4 -0
- package/dist/elements/problem/problemCheck.d.ts +166 -0
- package/dist/elements/problem/problemCheck.js +203 -0
- package/dist/elements/problem/problemContent.d.ts +2 -120
- package/dist/elements/problem/problemContent.js +2 -127
- package/dist/elements/problem/problemScript.d.ts +6 -1
- package/dist/resolve.d.ts +2 -1
- package/dist/resolve.js +8 -5
- package/package.json +2 -2
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { isRawElement } from "@jsprose/core";
|
|
2
|
+
import { defineResolveStep } from "../../resolveStep.js";
|
|
3
|
+
import { dependencySchema, depSchema } from "./dependency/core.js";
|
|
4
|
+
import { referenceSchema, refSchema } from "./reference/core.js";
|
|
5
|
+
export const contentLinkStep = defineResolveStep(({ rawElement, proseElement }) => {
|
|
6
|
+
if (!proseElement.id || !rawElement.storageKey) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
const checks = [
|
|
10
|
+
{
|
|
11
|
+
schema: depSchema,
|
|
12
|
+
key: "Dep"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
schema: dependencySchema,
|
|
16
|
+
key: "Dependency"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
schema: refSchema,
|
|
20
|
+
key: "Ref"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
schema: referenceSchema,
|
|
24
|
+
key: "Reference"
|
|
25
|
+
}
|
|
26
|
+
];
|
|
27
|
+
for (const { schema, key } of checks) {
|
|
28
|
+
if (isRawElement(rawElement, schema)) {
|
|
29
|
+
return {
|
|
30
|
+
storageKey: rawElement.storageKey,
|
|
31
|
+
label: rawElement.data.label.trim(),
|
|
32
|
+
type: key
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
});
|
|
@@ -2,7 +2,7 @@ import type { TopicPart } from '@erudit-js/core/content/topic';
|
|
|
2
2
|
import type { ContentType } from '@erudit-js/core/content/type';
|
|
3
3
|
import type { PreviewRequest } from '@erudit-js/core/preview/request';
|
|
4
4
|
import type { LinkToProp } from './core.js';
|
|
5
|
-
export type LinkStorageType = '
|
|
5
|
+
export type LinkStorageType = 'external' | 'contentItem' | 'unique';
|
|
6
6
|
interface LinkStorageBase {
|
|
7
7
|
type: LinkStorageType;
|
|
8
8
|
resolvedHref: string;
|
|
@@ -16,8 +16,8 @@ export type LinkStorageContent = {
|
|
|
16
16
|
} | {
|
|
17
17
|
contentType: Exclude<ContentType, 'topic'>;
|
|
18
18
|
});
|
|
19
|
-
export interface
|
|
20
|
-
type: '
|
|
19
|
+
export interface ExternalLinkStorage extends LinkStorageBase {
|
|
20
|
+
type: 'external';
|
|
21
21
|
}
|
|
22
22
|
export interface ContentItemLinkStorage extends LinkStorageBase {
|
|
23
23
|
type: 'contentItem';
|
|
@@ -29,6 +29,10 @@ export interface UniqueLinkStorage extends LinkStorageBase {
|
|
|
29
29
|
elementTitle?: string;
|
|
30
30
|
content: LinkStorageContent;
|
|
31
31
|
}
|
|
32
|
-
export
|
|
33
|
-
|
|
32
|
+
export interface ErrorLinkStorage {
|
|
33
|
+
type: 'error';
|
|
34
|
+
error: string;
|
|
35
|
+
}
|
|
36
|
+
export type LinkStorage = ExternalLinkStorage | ContentItemLinkStorage | UniqueLinkStorage | ErrorLinkStorage;
|
|
37
|
+
export declare function createLinkStorageKey(to: LinkToProp): string;
|
|
34
38
|
export {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { isUnique
|
|
1
|
+
import { isUnique } from "@jsprose/core";
|
|
2
2
|
import { parseDocumentId } from "@erudit-js/core/prose/documentId";
|
|
3
3
|
import { getGlobalContentPath, isGlobalContent } from "@erudit-js/core/content/global";
|
|
4
|
-
export function createLinkStorageKey(to
|
|
4
|
+
export function createLinkStorageKey(to) {
|
|
5
5
|
if (isUnique(to)) {
|
|
6
6
|
const documentId = parseDocumentId(to.documentId);
|
|
7
7
|
if (documentId.type === "contentPage") {
|
|
@@ -14,7 +14,7 @@ export function createLinkStorageKey(to, tagName) {
|
|
|
14
14
|
return `<link:global>/${getGlobalContentPath(to)}`;
|
|
15
15
|
}
|
|
16
16
|
if (typeof to === "string") {
|
|
17
|
-
return `<link:
|
|
17
|
+
return `<link:external>/${to}`;
|
|
18
18
|
}
|
|
19
|
-
|
|
19
|
+
return `<link:unknown>/${JSON.stringify(to)}`;
|
|
20
20
|
}
|
|
@@ -43,6 +43,9 @@ export const M = '_tag_';
|
|
|
43
43
|
*
|
|
44
44
|
* Use `freeze` prop to prevent line breaks in the rendered math (scrollbars will appear if the content overflows).
|
|
45
45
|
*
|
|
46
|
+
* You can also create flexible "breaking" gaps between expressions using `>>`, `>>{0|small|big|100px}` delimiters.
|
|
47
|
+
* Also you can specify the vertical aligment of such gaps using `>>{top|center|bottom}`.
|
|
48
|
+
*
|
|
46
49
|
* @title Block Math
|
|
47
50
|
* @layout block
|
|
48
51
|
* @example
|
|
@@ -54,6 +57,10 @@ export const M = '_tag_';
|
|
|
54
57
|
* <BlockMath freeze>{math`
|
|
55
58
|
* \lim\limits_{x \to \infty} \frac{1}{x} = 0
|
|
56
59
|
* `}</BlockMath>
|
|
60
|
+
*
|
|
61
|
+
* <BlockMath>{math`
|
|
62
|
+
* a^2 >> b^2 >>{big} c^2 >>{top} \sqrt{a^2 + b^2} >>{small}{bottom} \frac{a^2 + b^2}{c^2}
|
|
63
|
+
* `}</BlockMath>
|
|
57
64
|
* ```
|
|
58
65
|
*/
|
|
59
66
|
export const BlockMath = '_tag_';
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type TagChildren } from '@jsprose/core';
|
|
2
2
|
export declare const mathGroupTypes: readonly ["0", "small", "normal", "big"];
|
|
3
3
|
export type MathGroupGapType = (typeof mathGroupTypes)[number] | 'custom';
|
|
4
|
+
export type MathGroupAlignItems = 'top' | 'center' | 'bottom';
|
|
4
5
|
export interface MathGroupGapTemplate {
|
|
5
6
|
type: MathGroupGapType;
|
|
6
7
|
}
|
|
@@ -24,6 +25,7 @@ export type MathGroupGap = MathGroupGapZero | MathGroupGapSmall | MathGroupGapNo
|
|
|
24
25
|
export type MathGroupPart = string | MathGroup;
|
|
25
26
|
export interface MathGroup {
|
|
26
27
|
gap: MathGroupGap;
|
|
28
|
+
alignItems?: MathGroupAlignItems;
|
|
27
29
|
parts: MathGroupPart[];
|
|
28
30
|
}
|
|
29
31
|
export declare function resolveMathGroups(katex: string, isTopLevel?: boolean): Promise<MathGroup | string>;
|
|
@@ -7,71 +7,84 @@ export const mathGroupTypes = [
|
|
|
7
7
|
"normal",
|
|
8
8
|
"big"
|
|
9
9
|
];
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
const alignValues = [
|
|
11
|
+
"top",
|
|
12
|
+
"center",
|
|
13
|
+
"bottom"
|
|
14
|
+
];
|
|
15
|
+
function isAlignValue(value) {
|
|
16
|
+
return alignValues.includes(value);
|
|
17
|
+
}
|
|
18
|
+
function gapFromString(str) {
|
|
19
|
+
if (mathGroupTypes.includes(str)) {
|
|
20
|
+
return { type: str };
|
|
13
21
|
}
|
|
14
22
|
return {
|
|
15
23
|
type: "custom",
|
|
16
|
-
size:
|
|
24
|
+
size: str
|
|
17
25
|
};
|
|
18
26
|
}
|
|
19
27
|
function gapsEqual(gap1, gap2) {
|
|
20
|
-
if (gap1.type !== gap2.type)
|
|
21
|
-
return false;
|
|
22
|
-
}
|
|
28
|
+
if (gap1.type !== gap2.type) return false;
|
|
23
29
|
if (gap1.type === "custom" && gap2.type === "custom") {
|
|
24
30
|
return gap1.size === gap2.size;
|
|
25
31
|
}
|
|
26
32
|
return true;
|
|
27
33
|
}
|
|
28
34
|
export async function resolveMathGroups(katex, isTopLevel = true) {
|
|
29
|
-
// If whole string does not contain any groups, return default group with rendered math
|
|
30
35
|
if (!katex.includes(">>")) {
|
|
31
36
|
const rendered = await latexToHtml(katex, "block");
|
|
32
37
|
if (isTopLevel) {
|
|
33
|
-
// Only top-level should return a group
|
|
34
38
|
return {
|
|
35
39
|
gap: { type: "normal" },
|
|
36
40
|
parts: [rendered]
|
|
37
41
|
};
|
|
38
42
|
}
|
|
39
|
-
// Recursive left side should return a plain string
|
|
40
43
|
return rendered;
|
|
41
44
|
}
|
|
42
|
-
|
|
43
|
-
const delimiterRegex = />>(?:\{([^}]+)\})?/g;
|
|
45
|
+
const delimiterRegex = />>(?:\{([^}]+)\})?(?:\{([^}]+)\})?/g;
|
|
44
46
|
let match;
|
|
45
|
-
let
|
|
47
|
+
let last;
|
|
46
48
|
while ((match = delimiterRegex.exec(katex)) !== null) {
|
|
47
|
-
|
|
49
|
+
last = match;
|
|
50
|
+
}
|
|
51
|
+
const raw1 = last[1];
|
|
52
|
+
const raw2 = last[2];
|
|
53
|
+
let gap = { type: "normal" };
|
|
54
|
+
let alignItems;
|
|
55
|
+
// ---- Resolution rules ----
|
|
56
|
+
if (raw1 && raw2) {
|
|
57
|
+
// >>{gap}{align}
|
|
58
|
+
gap = gapFromString(raw1);
|
|
59
|
+
if (isAlignValue(raw2)) alignItems = raw2;
|
|
60
|
+
} else if (raw1) {
|
|
61
|
+
// >>{something}
|
|
62
|
+
if (isAlignValue(raw1)) {
|
|
63
|
+
// >>{center}
|
|
64
|
+
alignItems = raw1;
|
|
65
|
+
} else {
|
|
66
|
+
// >>{small} or custom gap
|
|
67
|
+
gap = gapFromString(raw1);
|
|
68
|
+
}
|
|
48
69
|
}
|
|
49
|
-
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
const
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
const leftPart = katex.slice(0, lastDelimiterPos);
|
|
56
|
-
const rightPart = katex.slice(lastDelimiterPos + lastDelimiterLen);
|
|
57
|
-
// Pushing rendered right part
|
|
58
|
-
const parts = [await latexToHtml(rightPart, "block")];
|
|
59
|
-
// Resolving left part
|
|
60
|
-
const leftGroup = await resolveMathGroups(leftPart, false);
|
|
70
|
+
const delimiterPos = last.index;
|
|
71
|
+
const delimiterLen = last[0].length;
|
|
72
|
+
const left = katex.slice(0, delimiterPos);
|
|
73
|
+
const right = katex.slice(delimiterPos + delimiterLen);
|
|
74
|
+
const parts = [await latexToHtml(right, "block")];
|
|
75
|
+
const leftGroup = await resolveMathGroups(left, false);
|
|
61
76
|
if (typeof leftGroup === "string") {
|
|
62
77
|
parts.unshift(leftGroup);
|
|
63
78
|
} else {
|
|
64
|
-
// Left part is a group, meaning it contains gaps
|
|
65
79
|
if (gapsEqual(leftGroup.gap, gap)) {
|
|
66
|
-
// If gaps are equal, we can merge the two groups into (current) one
|
|
67
80
|
parts.unshift(...leftGroup.parts);
|
|
68
81
|
} else {
|
|
69
|
-
// Gaps are different, we need to keep the left group as is
|
|
70
82
|
parts.unshift(leftGroup);
|
|
71
83
|
}
|
|
72
84
|
}
|
|
73
85
|
return {
|
|
74
86
|
gap,
|
|
87
|
+
...alignItems ? { alignItems } : {},
|
|
75
88
|
parts
|
|
76
89
|
};
|
|
77
90
|
}
|
|
@@ -7,7 +7,7 @@ const { mathGroup } = defineProps<{
|
|
|
7
7
|
freeze: boolean;
|
|
8
8
|
}>();
|
|
9
9
|
|
|
10
|
-
const
|
|
10
|
+
const gap = (() => {
|
|
11
11
|
switch (mathGroup.gap.type) {
|
|
12
12
|
case '0':
|
|
13
13
|
return '0px';
|
|
@@ -21,12 +21,29 @@ const columnGap = (() => {
|
|
|
21
21
|
return mathGroup.gap.size;
|
|
22
22
|
}
|
|
23
23
|
})();
|
|
24
|
+
|
|
25
|
+
const alignItems = (() => {
|
|
26
|
+
switch (mathGroup.alignItems ?? 'center') {
|
|
27
|
+
case 'top':
|
|
28
|
+
return 'flex-start';
|
|
29
|
+
case 'bottom':
|
|
30
|
+
return 'flex-end';
|
|
31
|
+
case 'center':
|
|
32
|
+
default:
|
|
33
|
+
return 'center';
|
|
34
|
+
}
|
|
35
|
+
})();
|
|
24
36
|
</script>
|
|
25
37
|
|
|
26
38
|
<template>
|
|
27
39
|
<div
|
|
28
|
-
:style="{
|
|
29
|
-
|
|
40
|
+
:style="{
|
|
41
|
+
'--mathGroupGap': gap,
|
|
42
|
+
gap: 'var(--mathGroupGap)',
|
|
43
|
+
rowGap: 'calc(var(--mathGroupGap)/2)',
|
|
44
|
+
alignItems,
|
|
45
|
+
}"
|
|
46
|
+
class="flex flex-wrap justify-center"
|
|
30
47
|
>
|
|
31
48
|
<template v-for="part of mathGroup.parts">
|
|
32
49
|
<Katex
|
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
import type { ProblemCustomAttribute as PAC } from './shared.js';
|
|
2
|
+
import type { ProblemRandom as _ProblemRandom } from './rng.js';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Problems are used to present exercises and questions to the reader.
|
|
5
|
-
* See the example for a full breakdown of the sub-elements available.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
7
|
+
* Allowed children inside `<Problem>`:
|
|
8
|
+
* - `<ProblemDescription>`
|
|
9
|
+
* - `<ProblemCheck>` (repeatable)
|
|
10
|
+
* - `<ProblemHint>` (repeatable)
|
|
11
|
+
* - `<ProblemAnswer>` (optionally with `<ProblemSection>`)
|
|
12
|
+
* - `<ProblemSolution>` (optionally with `<ProblemSection>`)
|
|
13
|
+
* - `<ProblemNote>` (optionally with `<ProblemSection>`)
|
|
8
14
|
*
|
|
9
15
|
* @title Problem
|
|
10
16
|
* @layout block
|
|
11
17
|
* @example
|
|
12
18
|
* ```tsx
|
|
13
|
-
* // Static problem
|
|
14
19
|
* <Problem title="Find the square" level="easy">
|
|
15
20
|
* <ProblemDescription>
|
|
16
21
|
* <P>What is the square of 2?</P>
|
|
@@ -40,52 +45,162 @@ import type { ProblemCustomAttribute as PAC } from './shared.js';
|
|
|
40
45
|
* </ProblemAnswer>
|
|
41
46
|
*
|
|
42
47
|
* <ProblemCheck label="The square of 2 is" answer={4} />
|
|
43
|
-
* // More checks...
|
|
44
48
|
*
|
|
45
49
|
* <ProblemNote>
|
|
46
50
|
* In fact, you can find the square of any number by multiplying it by itself!
|
|
47
51
|
* </ProblemNote>
|
|
48
52
|
* </Problem>
|
|
49
|
-
*
|
|
50
|
-
* // Script problem
|
|
51
|
-
* export const fooScript = defineProblemScript({
|
|
52
|
-
* isGenerator: true,
|
|
53
|
-
* })(({ initial, random }) => {
|
|
54
|
-
* const a = initial.nextInt(1, 10);
|
|
55
|
-
* const b = initial.nextInt(1, 10);
|
|
56
|
-
*
|
|
57
|
-
* return (
|
|
58
|
-
* <>
|
|
59
|
-
* <ProblemDescription>
|
|
60
|
-
* What is <M>{a} + {b}</M>?
|
|
61
|
-
* </ProblemDescription>
|
|
62
|
-
* <ProblemAnswer>
|
|
63
|
-
* <M>{a + b}</M>
|
|
64
|
-
* </ProblemAnswer>
|
|
65
|
-
* <ProblemCheck label="The answer is" answer={a + b} />
|
|
66
|
-
* </>
|
|
67
|
-
* );
|
|
68
|
-
* });
|
|
69
|
-
*
|
|
70
|
-
* <Problem title="Addition Problem" level="medium" script={fooScript} />
|
|
71
53
|
* ```
|
|
72
54
|
*/
|
|
73
55
|
export const Problem = '_tag_';
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Problem description.
|
|
59
|
+
*
|
|
60
|
+
* Can be used inside `<Problem>` or `<SubProblem>`.
|
|
61
|
+
*
|
|
62
|
+
* @title ProblemDescription
|
|
63
|
+
* @layout block
|
|
64
|
+
* @example
|
|
65
|
+
* ```tsx
|
|
66
|
+
* <ProblemDescription>
|
|
67
|
+
* <P>State the problem in your own words.</P>
|
|
68
|
+
* </ProblemDescription>
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
74
71
|
export const ProblemDescription = '_tag_';
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* A hint for the problem. Multiple hints can be provided.
|
|
75
|
+
*
|
|
76
|
+
* Can be used inside `<Problem>` or `<SubProblem>`.
|
|
77
|
+
*
|
|
78
|
+
* @title ProblemHint
|
|
79
|
+
* @layout block
|
|
80
|
+
* @example
|
|
81
|
+
* ```tsx
|
|
82
|
+
* <ProblemHint>
|
|
83
|
+
* <P>Try rewriting the expression in a simpler form.</P>
|
|
84
|
+
* </ProblemHint>
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
75
87
|
export const ProblemHint = '_tag_';
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* A titled section used inside `<ProblemSolution>` or `<ProblemAnswer>`.
|
|
91
|
+
*
|
|
92
|
+
* @title ProblemSection
|
|
93
|
+
* @layout block
|
|
94
|
+
* @example
|
|
95
|
+
* ```tsx
|
|
96
|
+
* <ProblemSection title="Method">
|
|
97
|
+
* <P>Show the steps.</P>
|
|
98
|
+
* </ProblemSection>
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
76
101
|
export const ProblemSection = '_tag_';
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* The problem solution.
|
|
105
|
+
*
|
|
106
|
+
* Can contain plain content and `<ProblemSection>` blocks.
|
|
107
|
+
* Can be used inside `<Problem>` or `<SubProblem>`.
|
|
108
|
+
*
|
|
109
|
+
* @title ProblemSolution
|
|
110
|
+
* @layout block
|
|
111
|
+
* @example
|
|
112
|
+
* ```tsx
|
|
113
|
+
* <ProblemSolution>
|
|
114
|
+
* <P>Start with the key idea.</P>
|
|
115
|
+
*
|
|
116
|
+
* <ProblemSection title="Details">
|
|
117
|
+
* <P>Then provide the full derivation.</P>
|
|
118
|
+
* </ProblemSection>
|
|
119
|
+
* </ProblemSolution>
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
77
122
|
export const ProblemSolution = '_tag_';
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* The final answer (usually concise).
|
|
126
|
+
*
|
|
127
|
+
* Can contain plain content and `<ProblemSection>` blocks.
|
|
128
|
+
* Can be used inside `<Problem>` or `<SubProblem>`.
|
|
129
|
+
*
|
|
130
|
+
* @title ProblemAnswer
|
|
131
|
+
* @layout block
|
|
132
|
+
* @example
|
|
133
|
+
* ```tsx
|
|
134
|
+
* <ProblemAnswer>
|
|
135
|
+
* <P><M>42</M></P>
|
|
136
|
+
* </ProblemAnswer>
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
78
139
|
export const ProblemAnswer = '_tag_';
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* A note shown after the checks/solution.
|
|
143
|
+
*
|
|
144
|
+
* Can be used inside `<Problem>` or `<SubProblem>`.
|
|
145
|
+
*
|
|
146
|
+
* @title ProblemNote
|
|
147
|
+
* @layout block
|
|
148
|
+
* @example
|
|
149
|
+
* ```tsx
|
|
150
|
+
* <ProblemNote>
|
|
151
|
+
* Remember to double-check units.
|
|
152
|
+
* </ProblemNote>
|
|
153
|
+
* ```
|
|
154
|
+
*/
|
|
79
155
|
export const ProblemNote = '_tag_';
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Defines an answer check for a problem.
|
|
159
|
+
*
|
|
160
|
+
* Can be used inside `<Problem>` or `<SubProblem>`.
|
|
161
|
+
*
|
|
162
|
+
* Validator props (exactly one per `<ProblemCheck>`):
|
|
163
|
+
* - `yes`: boolean-like answer, validated via locale yes/no patterns.
|
|
164
|
+
* - `no`: boolean-like answer, validated via locale yes/no patterns.
|
|
165
|
+
* - `answer`: exact expected value.
|
|
166
|
+
* - `number` -> numeric equality
|
|
167
|
+
* - `string` -> exact string match
|
|
168
|
+
* - `RegExp` -> `test()` match
|
|
169
|
+
* - `undefined` -> expects an empty answer
|
|
170
|
+
* - `answers`: multi-part answer (split by `separator`, default `,`, unordered by default).
|
|
171
|
+
* - Use `{ ordered, separator, values }` to configure matching.
|
|
172
|
+
* - Each position in `values` can be a single expected value or an array of expected values (any-of).
|
|
173
|
+
* - `script`: named script validator.
|
|
174
|
+
*
|
|
175
|
+
* You can nest `<ProblemCheck>` inside another `<ProblemCheck>` to group multiple checks.
|
|
176
|
+
*
|
|
177
|
+
* @title ProblemCheck
|
|
178
|
+
* @layout block
|
|
179
|
+
* @example
|
|
180
|
+
* ```tsx
|
|
181
|
+
* <ProblemCheck label="2 is even" yes />
|
|
182
|
+
* <ProblemCheck label="Enter nothing" answer={undefined} />
|
|
183
|
+
* <ProblemCheck label="The square of 2 is" answer={4} />
|
|
184
|
+
* <ProblemCheck
|
|
185
|
+
* label="Enter roots"
|
|
186
|
+
* answers={{ ordered: false, separator: ',', values: [2, [-2, /-?2/]] }}
|
|
187
|
+
* />
|
|
188
|
+
* <ProblemCheck script="myCustomValidator" />
|
|
189
|
+
*
|
|
190
|
+
* <ProblemCheck label="Grouped checks" yes>
|
|
191
|
+
* <ProblemCheck label="Also accept 42" answer={42} />
|
|
192
|
+
* </ProblemCheck>
|
|
193
|
+
* ```
|
|
194
|
+
*/
|
|
80
195
|
export const ProblemCheck = '_tag_';
|
|
81
196
|
|
|
82
197
|
/**
|
|
83
198
|
* Problem set is a collection of related problems presented together.
|
|
84
|
-
* `<Problems>` tag contains general problem information and insude can have multiple `<SubProblem>` tags.
|
|
85
199
|
*
|
|
86
|
-
*
|
|
200
|
+
* Allowed children inside `<Problems>`:
|
|
201
|
+
* - `<SubProblem>` (repeatable)
|
|
87
202
|
*
|
|
88
|
-
*
|
|
203
|
+
* Each `<SubProblem>` can contain the same child tags as `<Problem>`.
|
|
89
204
|
*
|
|
90
205
|
* @title Problems
|
|
91
206
|
* @layout block
|
|
@@ -104,9 +219,39 @@ export const ProblemCheck = '_tag_';
|
|
|
104
219
|
* ```
|
|
105
220
|
*/
|
|
106
221
|
export const Problems = '_tag_';
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* A single problem inside a `<Problems>` set.
|
|
225
|
+
*
|
|
226
|
+
* Allowed children inside `<SubProblem>`:
|
|
227
|
+
* - `<ProblemDescription>`
|
|
228
|
+
* - `<ProblemHint>` (repeatable)
|
|
229
|
+
* - `<ProblemSolution>` (optionally with `<ProblemSection>`)
|
|
230
|
+
* - `<ProblemAnswer>` (optionally with `<ProblemSection>`)
|
|
231
|
+
* - `<ProblemCheck>` (repeatable)
|
|
232
|
+
* - `<ProblemNote>`
|
|
233
|
+
*
|
|
234
|
+
* @title SubProblem
|
|
235
|
+
* @layout block
|
|
236
|
+
* @example
|
|
237
|
+
* ```tsx
|
|
238
|
+
* <SubProblem label="A">
|
|
239
|
+
* <ProblemDescription>
|
|
240
|
+
* <P>Solve for <M>x</M>.</P>
|
|
241
|
+
* </ProblemDescription>
|
|
242
|
+
*
|
|
243
|
+
* <ProblemCheck answer={42} />
|
|
244
|
+
* </SubProblem>
|
|
245
|
+
* ```
|
|
246
|
+
*/
|
|
107
247
|
export const SubProblem = '_tag_';
|
|
108
248
|
|
|
109
249
|
/**
|
|
110
250
|
* Typeguard for creating custom problem attributes.
|
|
111
251
|
*/
|
|
112
252
|
export type ProblemCustomAttribute = PAC;
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Typeguard for problem RNG.
|
|
256
|
+
*/
|
|
257
|
+
export type ProblemRandom = _ProblemRandom;
|
|
@@ -5,13 +5,6 @@ declare const _default: (import("../../app/appElement.js").AppElement<{
|
|
|
5
5
|
Data: import("./problem.js").ProblemData;
|
|
6
6
|
Storage: import("./storage.js").ProblemScriptStorage;
|
|
7
7
|
Children: import("./problemContent.js").ProblemContentChild[];
|
|
8
|
-
}> | import("../../app/appElement.js").AppElement<{
|
|
9
|
-
name: "subProblem";
|
|
10
|
-
type: "block";
|
|
11
|
-
linkable: false;
|
|
12
|
-
Data: import("./problems.js").SubProblemData;
|
|
13
|
-
Storage: import("./storage.js").ProblemScriptStorage;
|
|
14
|
-
Children: import("./problemContent.js").ProblemContentChild[];
|
|
15
8
|
}> | import("../../app/appElement.js").AppElement<{
|
|
16
9
|
name: "problems";
|
|
17
10
|
type: "block";
|
|
@@ -26,5 +19,12 @@ declare const _default: (import("../../app/appElement.js").AppElement<{
|
|
|
26
19
|
Storage: import("./storage.js").ProblemScriptStorage;
|
|
27
20
|
Children: import("./problemContent.js").ProblemContentChild[];
|
|
28
21
|
})[];
|
|
22
|
+
}> | import("../../app/appElement.js").AppElement<{
|
|
23
|
+
name: "subProblem";
|
|
24
|
+
type: "block";
|
|
25
|
+
linkable: false;
|
|
26
|
+
Data: import("./problems.js").SubProblemData;
|
|
27
|
+
Storage: import("./storage.js").ProblemScriptStorage;
|
|
28
|
+
Children: import("./problemContent.js").ProblemContentChild[];
|
|
29
29
|
}>)[];
|
|
30
30
|
export default _default;
|
|
@@ -1,27 +1,28 @@
|
|
|
1
1
|
import { defineEruditProseAppElement } from "../../app/appElement.js";
|
|
2
2
|
import { problemSchema } from "./problem.js";
|
|
3
3
|
import { problemsSchema, subProblemSchema } from "./problems.js";
|
|
4
|
+
const icon = () => import("./assets/icon.svg?raw");
|
|
4
5
|
export default [
|
|
5
6
|
defineEruditProseAppElement({
|
|
6
7
|
schema: problemSchema,
|
|
7
8
|
component: () => import("./components/Problem.vue"),
|
|
9
|
+
icon,
|
|
8
10
|
languages: {
|
|
9
|
-
en: () => import("./languages/en.js"),
|
|
10
|
-
ru: () => import("./languages/ru.js")
|
|
11
|
-
}
|
|
12
|
-
icon: () => import("./assets/icon.svg?raw")
|
|
13
|
-
}),
|
|
14
|
-
defineEruditProseAppElement({
|
|
15
|
-
schema: subProblemSchema,
|
|
16
|
-
component: () => import("./components/SubProblem.vue")
|
|
11
|
+
en: () => import("./languages/problem/en.js"),
|
|
12
|
+
ru: () => import("./languages/problem/ru.js")
|
|
13
|
+
}
|
|
17
14
|
}),
|
|
18
15
|
defineEruditProseAppElement({
|
|
19
16
|
schema: problemsSchema,
|
|
20
17
|
component: () => import("./components/Problems.vue"),
|
|
18
|
+
icon,
|
|
21
19
|
languages: {
|
|
22
|
-
en: () => import("./languages/en.js"),
|
|
23
|
-
ru: () => import("./languages/ru.js")
|
|
24
|
-
}
|
|
25
|
-
|
|
20
|
+
en: () => import("./languages/problems/en.js"),
|
|
21
|
+
ru: () => import("./languages/problems/ru.js")
|
|
22
|
+
}
|
|
23
|
+
}),
|
|
24
|
+
defineEruditProseAppElement({
|
|
25
|
+
schema: subProblemSchema,
|
|
26
|
+
component: () => import("./components/SubProblem.vue")
|
|
26
27
|
})
|
|
27
28
|
];
|